Search Unity

Null reference when trying to load the object create by AssetDatabase.CopyAsset() right after.

Discussion in 'Asset Database' started by Invertex, Sep 28, 2016.

  1. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    I'm doing some automated material assignment for our project, and in OnAssignMaterialModel() of the AssetPostprocessor, I'm doing an AssetDatabase.CopyAsset() of base versions of materials to be assigned to objects and then have a couple maps unique to that object assigned to it. The problem is, I can't seem to do a AssetDatabase.LoadAssetAtPath() on the copied object. It just returns null, even though if I go look in the folder, it has made a copy of the material.

    I've tried putting AssetDatabase.Refresh(), .SaveAssets() and .ImportAsset() before doing the load, and still no deal.

    Searching hasn't come up with much else, would greatly appreciate some help!
     
    Last edited: Sep 28, 2016
  2. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    I'm not 100% sure if this will fix it. But many times Unity is doing a lot of things behind the scenes that happen in between frames. Possibly some bookkeeping and or other asset management is being scheduled and performed between frames. Try adding a Coroutine that waits one frame and then calls your Load on the copied object.
     
  3. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    Doing it in a Coroutine doesn't seem to work either (though you can't use Coroutines in AssetImporter, so you need to setup Threads or use something like More Effective Coroutines). I even set it to while() loop on separate thread and do a Refresh(), ImportAssets(), SaveAssets() and LoadAssetAtPath() each frame but the loop would never exit despite the material clearly showing up in Unity. Perhaps this is a bug, I hope a Unity dev will read this thread. I'm using 5.4.1p1

    For now, I came up with a different solution that seems to work, by instead using AssetDatabase.CreateAsset to create my material where I want, setting it's shader to the one I want to copy from and using material.CopyPropertiesFromMaterial on it, then it is essentially a copy of my material, and I have access to it immediately. Here's the relevant part of my import code:

    Code (csharp):
    1. void OnPostprocessModel(GameObject obj)
    2. {
    3.     Material baseMatTmp = AssetDatabase.LoadAssetAtPath(baseMat, typeof(Material)) as Material;
    4.     Material newMat = new Material(baseMatTmp.shader);
    5.     AssetDatabase.CreateAsset(newMat, newMatPath);
    6.     newMat.CopyPropertiesFromMaterial(baseMatTmp);
    7.     //Now apply my unique maps to newMat and assign to the object being imported.
    8. }
     
    Last edited: Sep 29, 2016