Material isn't updated in Editor

I create a gameobject with an instanced material (hdrp/lit and transparent surface type) and assign the material. However, the modified material properties (compared to standard which is opaque) are only applied when I expand the material in the inspector.

How do you refresh the material / scene so that everything is up to date?

I tried EditorUtility.SetDirty and EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()) but nothing seemed to work.

Screenshots:

Gameobject and material creation. The grey rectangle should be transparent:

6161755--673792--m1.png

The material inspector is collapsed

6161755--673789--m2.png

Now I click the expand icon:

6161755--673786--m3.png

And all of a sudden the grey area has become transparent:

6161755--673795--m4.png

What happens on the expanding of the material inspector that I need to apply?

Do you have “Always Refresh” checked (above scene view)?
6161767--673804--always_refresh.jpg

1 Like

I don’t have that option in 2020.1.0f1:

6161779--673807--ar.png

I think Always Refresh is the same as Animated Materials - if you have that checked, does the problem persist?

Yeah, tried it, didn’t help.

I created a quick reproduction case which creates 2 spheres with materials. One Opaque, the other Transparent:

using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;

public class MaterialTest : MonoBehaviour
{
    [MenuItem("MaterialTest/Create", false, 10)]
    static void CreateCustomGameObject(MenuCommand menuCommand)
    {
        CreateOpaqueSphere();
        CreateTransparentSphere();
    }

    static void CreateOpaqueSphere()
    {
        GameObject go = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        go.name = "Opaque Sphere";
        go.transform.position = new Vector3(0, 0, 0);

        var unityMaterial = new UnityEngine.Material(Shader.Find("HDRP/Lit"));

        unityMaterial.SetFloat("_SurfaceType", 0); // 0 = Opaque; 1 = Transparent
        unityMaterial.SetFloat("_Metallic", 1f);
        unityMaterial.SetFloat("_Smoothness", 1f);

        unityMaterial.renderQueue = -1;

        go.GetComponent<Renderer>().sharedMaterial = unityMaterial;

        EditorUtility.SetDirty(go);
        EditorUtility.SetDirty(unityMaterial);
        EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
    }

    static void CreateTransparentSphere()
    {
        GameObject go = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        go.name = "Transparent Sphere";
        go.transform.position = new Vector3(2, 0, 0);

        var unityMaterial = new UnityEngine.Material(Shader.Find("HDRP/Lit"));

        unityMaterial.EnableKeyword("_BLENDMODE_PRESERVE_SPECULAR_LIGHTING");
        unityMaterial.EnableKeyword("_BLENDMODE_PRE_MULTIPLY");
        unityMaterial.EnableKeyword("_ENABLE_FOG_ON_TRANSPARENT");
        unityMaterial.EnableKeyword("_NORMALMAP_TANGENT_SPACE");
        unityMaterial.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");

        unityMaterial.SetColor("_BaseColor", new Color(128, 0, 0, 0f));
        unityMaterial.SetFloat("_SurfaceType", 1); // 0 = Opaque; 1 = Transparent
        unityMaterial.SetFloat("_Metallic", 1f);
        unityMaterial.SetFloat("_Smoothness", 1f);

        unityMaterial.renderQueue = 3000;

        go.GetComponent<Renderer>().sharedMaterial = unityMaterial;

        EditorUtility.SetDirty(go);
        EditorUtility.SetDirty(unityMaterial);
        EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
    }
}

In the main menu click MaterialTest → Create. You’ll get this:


As soon as you open the material of the Transparent Sphere in the inspector nothing happens in opposite to the above mentioned bug description. But when I edit the color and set the transparency value to the same value, it starts to look like it should:

Something I’m missing, I just don’t know what.

1 Like

Hey Rowlan, I can send this post over, if you think this is a bug please report it as well - https://unity3d.com/unity/qa/bug-reporting

Awesome, I created one, thank you very much! Ticket number is 1268504

By the way, I dug through the hdrp code and it appears that some reset is happening there that I’m missing. I tried almost everything in there, but yet didn’t find a solution. It shouldn’t even be needed imo. Problem is also I have no access to e. g. ApplyKeywordsAndPassesIfNeeded which seems to be used in the material inspector of LitGUI.cs to fix the material:

        protected void ApplyKeywordsAndPassesIfNeeded(bool changed, Material[] materials)
        {
            // !!! HACK !!!
            // When a user creates a new Material from the contextual menu, the material is created from the editor code and the appropriate shader is applied to it.
            // This means that we never setup keywords and passes for a newly created material. The material is then in an invalid state.
            // To work around this, as the material is automatically selected when created, we force an update of the keyword at the first "frame" of the editor.

            // Apply material keywords and pass:
            if (changed || m_FirstFrame)
            {
                m_FirstFrame = false;

                foreach (var material in materials)
                    SetupMaterialKeywordsAndPassInternal(material);
            }
        }

I also saw this necessary:

        // This is a hack for GI. PVR looks in the shader for a texture named "_MainTex" to extract the opacity of the material for baking. In the same manner, "_Cutoff" and "_Color" are also necessary.
        // Since we don't have those parameters in our shaders we need to provide a "fake" useless version of them with the right values for the GI to work.
        public static void SetupMainTexForAlphaTestGI(this Material material, string colorMapPropertyName, string colorPropertyName)
        {
            if (material.HasProperty(colorMapPropertyName))
            {
                var mainTex = material.GetTexture(colorMapPropertyName);
                material.SetTexture("_MainTex", mainTex);
            }

            if (material.HasProperty(colorPropertyName))
            {
                var color = material.GetColor(colorPropertyName);
                material.SetColor("_Color", color);
            }

            if (material.HasProperty("_AlphaCutoff")) // Same for all our materials
            {
                var cutoff = material.GetFloat("_AlphaCutoff");
                material.SetFloat("_Cutoff", cutoff);
            }
        }

which is used for

            material.SetupMainTexForAlphaTestGI("_BaseColorMap", "_BaseColor");

I left the example code simple nontheless because neither of those above solved it.

But I can’t tell if that’s even the part that refreshes the material in the end.

If there is no other solution the main goal would be to explicitly invoke some kind of fix / refresh on a material to force the editor to look exactly like the build.

@Shaunyowns I found the problem with the color, it was actually a noob mistake. I’m importing values from an external interface which are color values from 0-255. But Unity uses 0-1.

However transparency is only updated when i open the material in the material inspector and click the arrow down, i. e. I’m back to the problem in the initial post.

@Shaunyowns Got it now. ZWrite wasn’t set to 10.

I simply did a comparison of the properties using a script I made , i. e. compared what I created to what the material inspector fixed. It would still be preferred to have some kind of utility method that fixed a material.

How can I close the ticket?

Thank you very much!

Hello @Rowlan , sorry to bother you, I have a similar problem with a new plugins I’m using.
From what I saw the plugin use a created shader from shader graph, but when it generates the material (all the gameobject are generated at play) it seems like the transparent settings aren’t correctly set, until I open it from inspector. What did you change to make it work ?

The problem is that Unity fixes missing material settings implicitly when you expand the material settings in the inspector. That’s super bad, one can never find errors this way. What I did was compare the material settings before and after I opened it in the inspector and then I added the missing parts in my code. However since you say you use shader graph, it should work out of the box. My problem was just for the case when I changed material settings via code.

Oh okay ! Yeah the shader in itself seems fine since I don’t modify it, but in play it just seems like I need to refresh it because it disable Keyword or properties.

Thx for the quick answer ;).

I have the same issue with changing transparency mode and it not updating until clicking the material in inspector. Glad I’m not the only one.

I also have this same bug and its really not possible to fix unless unity finds a way to update their material for a transparent surface type. This is actually a major bug and should be fixed. I also know this problem has been around for years and nothing has been done about it.

One recommendation i would suggest would be to define your material surface types as material templates in the project. Then use the resource.load technique and cache them on start-up. This is obviosly a good approach if you dont have many permutations of keywords your working with. I still not tested if this corrects the editor material instancing issue but worth a try. [ WORKS FINE, JUST TESTED ]

For example

            _materials = new Dictionary<string, Material>();
            _materials.Add(HDRP_UNLIT_OPAQUE, Resources.Load<Material>(matTemplatePath + HDRP_UNLIT_OPAQUE));
            _materials.Add(HDRP_UNLIT_OPAQUE_DOUBLE, Resources.Load<Material>(matTemplatePath + HDRP_UNLIT_OPAQUE_DOUBLE));
            _materials.Add(HDRP_UNLIT_TRANS, Resources.Load<Material>(matTemplatePath + HDRP_UNLIT_TRANS));
            _materials.Add(HDRP_UNLIT_TRANS_DOUBLE, Resources.Load<Material>(matTemplatePath + HDRP_UNLIT_TRANS_DOUBLE));
            _materials.Add(HDRP_LIT_OPAQUE, Resources.Load<Material>(matTemplatePath + HDRP_LIT_OPAQUE));
            _materials.Add(HDRP_LIT_OPAQUE, Resources.Load<Material>(matTemplatePath + HDRP_LIT_OPAQUE_DOUBLE));
            _materials.Add(HDRP_LIT_TRANS, Resources.Load<Material>(matTemplatePath + HDRP_LIT_TRANS));
            _materials.Add(HDRP_LIT_TRANS_DOUBLE, Resources.Load<Material>(matTemplatePath + HDRP_LIT_TRANS_DOUBLE));
1 Like

Quick update on my last post which works in HDRP

HDRP stores all its rendering setup in the material properties

This function will ensure that our material is always using the correct keyword setup for those properties.

#if UNITY_EDITOR
HDShaderUtils.ResetMaterialKeywords(materials[j]);
#endif

2 Likes

I tried @Rowlan script, unfortunately it didn’t find any difference, I tried to reset material keywords

@GXMark That FIXED my issue, thank you sir.

This works as long as you are in the editor, for a release build it doesn’t since it needs to be running on the editor. Has anyone find a way to reset the material keywords on a build? I do fbx and material setup at runtime, tried taking notes on the shader keywords after the reset on the editor and forcing them on material.EnableKeywords() for the build but it isn’t working. Using Unity 2020.3.15f2 and HDRP 10.5.1 with the Lit Shader

Hello, you can find documentation on material setup here.
Essentially HDRP materials need to have some keywords and properties set up before they can be rendered correctly.
In the editor this step is done automatically when showing the inspector. For materials created from scripts it is not automatic.

Starting from HDRP 13 you have access to the following API: HDMaterial.ValidateMaterial(material);
that does the setup
For older versions, you can use the following one, but it’s only available in the editor (not at runtime): HDShaderUtils.ResetMaterialKeywords(material)

1 Like

If you want proper material setup at editor and runtime in standard, URP and HDRP then the way i do it is simply to create a resources materials folder in your project view and simply reinstance the different flavours you desire.

Material mat = new Material(Resources.Load(path);

Note that any materials you define in the resources folder will automatically get prepared at runtime for you during a build.