Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Material changes made via script in editor are reset on save.

Discussion in 'Scripting' started by RedVonix, Apr 27, 2022.

  1. RedVonix

    RedVonix

    Joined:
    Dec 13, 2011
    Posts:
    414
    Unity Version: 2021.1.22f1

    I'm working on some code where we open a Material via AssetDatabase.LoadAssetAtPath, change its properties, and then save it. This seems like it should work - but when the save occurs, the material is reset to its original state.

    Here is my code:

    Code (CSharp):
    1. string materialPath; // This is a proper and proven material path.
    2.  
    3. Texture2D loadedTexture; // A texture that exists from the project.
    4.  
    5. Material targMat = AssetDatabase.LoadAssetAtPath(materialPath, typeof(Material)) as Material;
    6.  
    7. targMat.SetTexture("_BaseMap", loadedTexture);
    8. targMat.SetColor("_BaseColor", Color.red);
    That code by itself works great. The material in the Project tab shows the changes successfully applied. Any objects in the scene that use that material show the changes. However, if I now Save Scene or Save Project - both the texture and the color reset to what they were before making the above changes.

    You're probably saying, "But Red - you need to set it dirty and save it!" and I would say - ah hah - I have tried that! And alas, it doesn't work. So to do that, I add the following code to the bottom of what I posted above:

    Code (CSharp):
    1.  
    2. EditorUtility.SetDirty(targMat);
    3. AssetDatabase.SaveAssetIfDirty(targMat);
    Now when I add this - the Material _IMMEDIATELY_ reverts to its original state. Meaning the changes do get set, and do get applied, but as soon as I call SaveAsset, the values are reset.

    I'm pretty stuck at this point, and I'm wondering if I'm doing this wrong, or if this is a Unity bug. Any tips or advice would be fantastic - thank you!
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,951
  3. Streamfall

    Streamfall

    Joined:
    Aug 8, 2011
    Posts:
    43
    You might try something like this :
    Material material = new Material(Shader.Find("Specular"));

    Then get / modify the Material... then save it.
    Something about creating a new Material reminded me of how instances of objects are. A Material Object isn't always a Material Object.

    Here's the relatable example :
    https://docs.unity3d.com/ScriptReference/AssetDatabase.SaveAssets.html
     
  4. RedVonix

    RedVonix

    Joined:
    Dec 13, 2011
    Posts:
    414
    In the end, the only thing I found that worked was rebuilding the Material as a new object every time, deleting the old, and replacing it with the new. Thanks everyone!
     
    Kurt-Dekker likes this.
  5. Tom_Olsen

    Tom_Olsen

    Joined:
    Oct 11, 2020
    Posts:
    7
    Sorry, late reply, but did you actualy define the properties your setting in the property section of your shader?
    If you only define them inside the shader pass they will not be serialized and yield the exact behaviour your describing.
     
  6. oleg_v

    oleg_v

    Joined:
    Nov 10, 2017
    Posts:
    68
    Sorry for late update and a bit different problem (But IMHO related because it's unique google link related to "Materials are not updated after update them from Editor script").

    I have a bit different case:
    • Create materials from editor script, from given template, assign them to renderer
    • Update renderer sharedMaterials properties via Custom Editor

    Actual (on scene reload):
    • Properties are saved for my component from Custom Editor
    • Material properties are reset to default

    Expected:
    • Both component and materials properties are saved.

    Side note: since all my materials are non-assets, probbaly reason for reset is that Unity can't save changed material properties to scene. So Unity need a real material stored in assets.

    Solved by using MaterialPropertyBlocks for changed properties. Renderer is saved fine.