Standard shader with depth buffer (Base for Ghost/Spirit effect)

Hello all,

I just wish to share a “little” modification I did to the standard shaders of Unity5.
While it’s really simple, I think many people should really like it as it work perfectly well with anything you have already built with the standard shader (or Standard Specular) since it makes uses of its modular shader system.

Create a C-Sharp script in your Unity project and name it “StandardShaderGUI.cs”

Copy-paste the following code into it :
Display code

using System;
using UnityEngine;

namespace UnityEditor
{
internal class StandardShaderGUI : ShaderGUI
{
    private enum WorkflowMode
    {
        Specular,
        Metallic,
        Dielectric
    }

    public enum BlendMode
    {
        Opaque,
        Cutout,
        Fade,        // Old school alpha-blending mode, fresnel does not affect amount of transparency
        Transparent, // Physically plausible transparency mode, implemented as alpha pre-multiply
        Ghost
    }

    private static class Styles
    {
        public static GUIStyle optionsButton = "PaneOptions";
        public static GUIContent uvSetLabel = new GUIContent("UV Set");
        public static GUIContent[] uvSetOptions = new GUIContent[] { new GUIContent("UV channel 0"), new GUIContent("UV channel 1") };

        public static string emptyTootip = "";
        public static GUIContent albedoText = new GUIContent("Albedo", "Albedo (RGB) and Transparency (A)");
        public static GUIContent alphaCutoffText = new GUIContent("Alpha Cutoff", "Threshold for alpha cutoff");
        public static GUIContent specularMapText = new GUIContent("Specular", "Specular (RGB) and Smoothness (A)");
        public static GUIContent metallicMapText = new GUIContent("Metallic", "Metallic (R) and Smoothness (A)");
        public static GUIContent smoothnessText = new GUIContent("Smoothness", "");
        public static GUIContent normalMapText = new GUIContent("Normal Map", "Normal Map");
        public static GUIContent heightMapText = new GUIContent("Height Map", "Height Map (G)");
        public static GUIContent occlusionText = new GUIContent("Occlusion", "Occlusion (G)");
        public static GUIContent emissionText = new GUIContent("Emission", "Emission (RGB)");
        public static GUIContent detailMaskText = new GUIContent("Detail Mask", "Mask for Secondary Maps (A)");
        public static GUIContent detailAlbedoText = new GUIContent("Detail Albedo x2", "Albedo (RGB) multiplied by 2");
        public static GUIContent detailNormalMapText = new GUIContent("Normal Map", "Normal Map");

        public static string whiteSpaceString = " ";
        public static string primaryMapsText = "Main Maps";
        public static string secondaryMapsText = "Secondary Maps";
        public static string renderingMode = "Rendering Mode";
        public static GUIContent emissiveWarning = new GUIContent ("Emissive value is animated but the material has not been configured to support emissive. Please make sure the material itself has some amount of emissive.");
        public static GUIContent emissiveColorWarning = new GUIContent ("Ensure emissive color is non-black for emission to have effect.");
        public static readonly string[] blendNames = Enum.GetNames (typeof (BlendMode));
    }

    MaterialProperty blendMode = null;
    MaterialProperty albedoMap = null;
    MaterialProperty albedoColor = null;
    MaterialProperty alphaCutoff = null;
    MaterialProperty specularMap = null;
    MaterialProperty specularColor = null;
    MaterialProperty metallicMap = null;
    MaterialProperty metallic = null;
    MaterialProperty smoothness = null;
    MaterialProperty bumpScale = null;
    MaterialProperty bumpMap = null;
    MaterialProperty occlusionStrength = null;
    MaterialProperty occlusionMap = null;
    MaterialProperty heigtMapScale = null;
    MaterialProperty heightMap = null;
    MaterialProperty emissionColorForRendering = null;
    MaterialProperty emissionMap = null;
    MaterialProperty detailMask = null;
    MaterialProperty detailAlbedoMap = null;
    MaterialProperty detailNormalMapScale = null;
    MaterialProperty detailNormalMap = null;
    MaterialProperty uvSetSecondary = null;

    MaterialEditor m_MaterialEditor;
    WorkflowMode m_WorkflowMode = WorkflowMode.Specular;
    ColorPickerHDRConfig m_ColorPickerHDRConfig = new ColorPickerHDRConfig(0f, 99f, 1/99f, 3f);

    bool m_FirstTimeApply = true;

    public void FindProperties (MaterialProperty[] props)
    {
        blendMode = FindProperty ("_Mode", props);
        albedoMap = FindProperty ("_MainTex", props);
        albedoColor = FindProperty ("_Color", props);
        alphaCutoff = FindProperty ("_Cutoff", props);
        specularMap = FindProperty ("_SpecGlossMap", props, false);
        specularColor = FindProperty ("_SpecColor", props, false);
        metallicMap = FindProperty ("_MetallicGlossMap", props, false);
        metallic = FindProperty ("_Metallic", props, false);
        if (specularMap != null && specularColor != null)
            m_WorkflowMode = WorkflowMode.Specular;
        else if (metallicMap != null && metallic != null)
            m_WorkflowMode = WorkflowMode.Metallic;
        else
            m_WorkflowMode = WorkflowMode.Dielectric;
        smoothness = FindProperty ("_Glossiness", props);
        bumpScale = FindProperty ("_BumpScale", props);
        bumpMap = FindProperty ("_BumpMap", props);
        heigtMapScale = FindProperty ("_Parallax", props);
        heightMap = FindProperty("_ParallaxMap", props);
        occlusionStrength = FindProperty ("_OcclusionStrength", props);
        occlusionMap = FindProperty ("_OcclusionMap", props);
        emissionColorForRendering = FindProperty ("_EmissionColor", props);
        emissionMap = FindProperty ("_EmissionMap", props);
        detailMask = FindProperty ("_DetailMask", props);
        detailAlbedoMap = FindProperty ("_DetailAlbedoMap", props);
        detailNormalMapScale = FindProperty ("_DetailNormalMapScale", props);
        detailNormalMap = FindProperty ("_DetailNormalMap", props);
        uvSetSecondary = FindProperty ("_UVSec", props);
    }

    public override void OnGUI (MaterialEditor materialEditor, MaterialProperty[] props)
    {
        FindProperties (props); // MaterialProperties can be animated so we do not cache them but fetch them every event to ensure animated values are updated correctly
        m_MaterialEditor = materialEditor;
        Material material = materialEditor.target as Material;

        ShaderPropertiesGUI (material);

        // Make sure that needed keywords are set up if we're switching some existing
        // material to a standard shader.
        if (m_FirstTimeApply)
        {
            SetMaterialKeywords (material, m_WorkflowMode);
            m_FirstTimeApply = false;
        }
    }

    public void ShaderPropertiesGUI (Material material)
    {
        // Use default labelWidth
        EditorGUIUtility.labelWidth = 0f;

        // Detect any changes to the material
        EditorGUI.BeginChangeCheck();
        {
            BlendModePopup();

            // Primary properties
            GUILayout.Label (Styles.primaryMapsText, EditorStyles.boldLabel);
            DoAlbedoArea(material);
            DoSpecularMetallicArea();
            m_MaterialEditor.TexturePropertySingleLine(Styles.normalMapText, bumpMap, bumpMap.textureValue != null ? bumpScale : null);
            m_MaterialEditor.TexturePropertySingleLine(Styles.heightMapText, heightMap, heightMap.textureValue != null ? heigtMapScale : null);
            m_MaterialEditor.TexturePropertySingleLine(Styles.occlusionText, occlusionMap, occlusionMap.textureValue != null ? occlusionStrength : null);
            DoEmissionArea(material);
            m_MaterialEditor.TexturePropertySingleLine(Styles.detailMaskText, detailMask);
            EditorGUI.BeginChangeCheck();
            m_MaterialEditor.TextureScaleOffsetProperty(albedoMap);
            if (EditorGUI.EndChangeCheck())
                emissionMap.textureScaleAndOffset = albedoMap.textureScaleAndOffset; // Apply the main texture scale and offset to the emission texture as well, for Enlighten's sake

            EditorGUILayout.Space();

            // Secondary properties
            GUILayout.Label(Styles.secondaryMapsText, EditorStyles.boldLabel);
            m_MaterialEditor.TexturePropertySingleLine(Styles.detailAlbedoText, detailAlbedoMap);
            m_MaterialEditor.TexturePropertySingleLine(Styles.detailNormalMapText, detailNormalMap, detailNormalMapScale);
            m_MaterialEditor.TextureScaleOffsetProperty(detailAlbedoMap);
            m_MaterialEditor.ShaderProperty(uvSetSecondary, Styles.uvSetLabel.text);
        }
        if (EditorGUI.EndChangeCheck())
        {
            foreach (var obj in blendMode.targets)
                MaterialChanged((Material)obj, m_WorkflowMode);
        }
    }

    internal void DetermineWorkflow(MaterialProperty[] props)
    {
        if (FindProperty("_SpecGlossMap", props, false) != null && FindProperty("_SpecColor", props, false) != null)
            m_WorkflowMode = WorkflowMode.Specular;
        else if (FindProperty("_MetallicGlossMap", props, false) != null && FindProperty("_Metallic", props, false) != null)
            m_WorkflowMode = WorkflowMode.Metallic;
        else
            m_WorkflowMode = WorkflowMode.Dielectric;
    }

    public override void AssignNewShaderToMaterial (Material material, Shader oldShader, Shader newShader)
    {
        // _Emission property is lost after assigning Standard shader to the material
        // thus transfer it before assigning the new shader
        if (material.HasProperty("_Emission"))
        {
            material.SetColor("_EmissionColor", material.GetColor("_Emission"));
        }

        base.AssignNewShaderToMaterial(material, oldShader, newShader);

        if (oldShader == null || !oldShader.name.Contains("Legacy Shaders/"))
            return;

        BlendMode blendMode = BlendMode.Opaque;
        if (oldShader.name.Contains("/Transparent/Cutout/"))
        {
            blendMode = BlendMode.Cutout;
        }
        else if (oldShader.name.Contains("/Transparent/"))
        {
            // NOTE: legacy shaders did not provide physically based transparency
            // therefore Fade mode
            blendMode = BlendMode.Fade;
        }
        material.SetFloat("_Mode", (float)blendMode);

        DetermineWorkflow( MaterialEditor.GetMaterialProperties (new Material[] { material }) );
        MaterialChanged(material, m_WorkflowMode);
    }

    void BlendModePopup()
    {
        EditorGUI.showMixedValue = blendMode.hasMixedValue;
        var mode = (BlendMode)blendMode.floatValue;

        EditorGUI.BeginChangeCheck();
        mode = (BlendMode)EditorGUILayout.Popup(Styles.renderingMode, (int)mode, Styles.blendNames);
        if (EditorGUI.EndChangeCheck())
        {
            m_MaterialEditor.RegisterPropertyChangeUndo("Rendering Mode");
            blendMode.floatValue = (float)mode;
        }

        EditorGUI.showMixedValue = false;
    }

    void DoAlbedoArea(Material material)
    {
        m_MaterialEditor.TexturePropertySingleLine(Styles.albedoText, albedoMap, albedoColor);
        if (((BlendMode)material.GetFloat("_Mode") == BlendMode.Cutout))
        {
            m_MaterialEditor.ShaderProperty(alphaCutoff, Styles.alphaCutoffText.text, MaterialEditor.kMiniTextureFieldLabelIndentLevel+1);
        }
    }

    void DoEmissionArea(Material material)
    {
        float brightness = emissionColorForRendering.colorValue.maxColorComponent;
        bool showHelpBox = !HasValidEmissiveKeyword(material);
        bool showEmissionColorAndGIControls = brightness > 0.0f;
      
        bool hadEmissionTexture = emissionMap.textureValue != null;

        // Texture and HDR color controls
        m_MaterialEditor.TexturePropertyWithHDRColor(Styles.emissionText, emissionMap, emissionColorForRendering, m_ColorPickerHDRConfig, false);

        // If texture was assigned and color was black set color to white
        if (emissionMap.textureValue != null && !hadEmissionTexture && brightness <= 0f)
            emissionColorForRendering.colorValue = Color.white;

        // Dynamic Lightmapping mode
        if (showEmissionColorAndGIControls)
        {
            bool shouldEmissionBeEnabled = ShouldEmissionBeEnabled(emissionColorForRendering.colorValue);
            EditorGUI.BeginDisabledGroup(!shouldEmissionBeEnabled);

            m_MaterialEditor.LightmapEmissionProperty (MaterialEditor.kMiniTextureFieldLabelIndentLevel + 1);

            EditorGUI.EndDisabledGroup();
        }

        if (showHelpBox)
        {
            EditorGUILayout.HelpBox(Styles.emissiveWarning.text, MessageType.Warning);
        }
    }

    void DoSpecularMetallicArea()
    {
        if (m_WorkflowMode == WorkflowMode.Specular)
        {
            if (specularMap.textureValue == null)
                m_MaterialEditor.TexturePropertyTwoLines(Styles.specularMapText, specularMap, specularColor, Styles.smoothnessText, smoothness);
            else
                m_MaterialEditor.TexturePropertySingleLine(Styles.specularMapText, specularMap);

        }
        else if (m_WorkflowMode == WorkflowMode.Metallic)
        {
            if (metallicMap.textureValue == null)
                m_MaterialEditor.TexturePropertyTwoLines(Styles.metallicMapText, metallicMap, metallic, Styles.smoothnessText, smoothness);
            else
                m_MaterialEditor.TexturePropertySingleLine(Styles.metallicMapText, metallicMap);
        }
    }

    public static void SetupMaterialWithBlendMode(Material material, BlendMode blendMode)
    {
        switch (blendMode)
        {
            case BlendMode.Opaque:
                material.SetOverrideTag("RenderType", "");
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = -1;
                break;
            case BlendMode.Cutout:
                material.SetOverrideTag("RenderType", "TransparentCutout");
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.EnableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 2450;
                break;
            case BlendMode.Fade:
                material.SetOverrideTag("RenderType", "Transparent");
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                material.SetInt("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.EnableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 3000;
                break;
            case BlendMode.Transparent:
                material.SetOverrideTag("RenderType", "Transparent");
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                material.SetInt("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 3000;
                break;
            case BlendMode.Ghost:
                material.SetOverrideTag("RenderType", "Transparent");
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                material.SetInt("_ZWrite", 1);
                material.DisableKeyword("_ALPHATEST_ON");
                material.EnableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 3000;
                break;
        }
    }
  
    static bool ShouldEmissionBeEnabled (Color color)
    {
        return color.maxColorComponent > (0.1f / 255.0f);
    }

    static void SetMaterialKeywords(Material material, WorkflowMode workflowMode)
    {
        // Note: keywords must be based on Material value not on MaterialProperty due to multi-edit & material animation
        // (MaterialProperty value might come from renderer material property block)
        SetKeyword (material, "_NORMALMAP", material.GetTexture ("_BumpMap") || material.GetTexture ("_DetailNormalMap"));
        if (workflowMode == WorkflowMode.Specular)
            SetKeyword (material, "_SPECGLOSSMAP", material.GetTexture ("_SpecGlossMap"));
        else if (workflowMode == WorkflowMode.Metallic)
            SetKeyword (material, "_METALLICGLOSSMAP", material.GetTexture ("_MetallicGlossMap"));
        SetKeyword (material, "_PARALLAXMAP", material.GetTexture ("_ParallaxMap"));
        SetKeyword (material, "_DETAIL_MULX2", material.GetTexture ("_DetailAlbedoMap") || material.GetTexture ("_DetailNormalMap"));

        bool shouldEmissionBeEnabled = ShouldEmissionBeEnabled (material.GetColor("_EmissionColor"));
        SetKeyword (material, "_EMISSION", shouldEmissionBeEnabled);

        // Setup lightmap emissive flags
        MaterialGlobalIlluminationFlags flags = material.globalIlluminationFlags;
        if ((flags & (MaterialGlobalIlluminationFlags.BakedEmissive | MaterialGlobalIlluminationFlags.RealtimeEmissive)) != 0)
        {
            flags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack;
            if (!shouldEmissionBeEnabled)
                flags |= MaterialGlobalIlluminationFlags.EmissiveIsBlack;

            material.globalIlluminationFlags = flags;
        }
    }

    bool HasValidEmissiveKeyword (Material material)
    {
        // Material animation might be out of sync with the material keyword.
        // So if the emission support is disabled on the material, but the property blocks have a value that requires it, then we need to show a warning.
        // (note: (Renderer MaterialPropertyBlock applies its values to emissionColorForRendering))
        bool hasEmissionKeyword = material.IsKeywordEnabled ("_EMISSION");
        if (!hasEmissionKeyword && ShouldEmissionBeEnabled (emissionColorForRendering.colorValue))
            return false;
        else
            return true;
    }

    static void MaterialChanged(Material material, WorkflowMode workflowMode)
    {
        SetupMaterialWithBlendMode(material, (BlendMode)material.GetFloat("_Mode"));

        SetMaterialKeywords(material, workflowMode);
    }

    static void SetKeyword(Material m, string keyword, bool state)
    {
        if (state)
            m.EnableKeyword (keyword);
        else
            m.DisableKeyword (keyword);
    }
}

} // namespace UnityEditor

This will replace the current StandardShaderGUI script which is hidden within the engine itself and manage the Standard and Standard(Specular) GUI options. (You can get a copy of its original file through the website archive. The script is located in the “Editor” folder of the ZIP file.) If you ever have any issues with this, just deleting the file from your project will make it use the original hidden file and all will be back to what you had before adding the script.

This script will add a 5th option in the rendering mode :

There aren’t any additional texture required, but the result will be quite different as this option will activate the dept buffer of the material (as it is used with Opaque and Cutout).

There’s an example of the differences (the transparency is managed through the Albedo alpha channel) :

As you might notice, the transparency is now a lot better for the character (lower right corner) as the head and hand doesn’t fuse together anymore.

I know that this is nothing “new”, but as I was looking around, I didn’t found anything regarding this way of adding the option into the engine so… there you go. :slight_smile:

If anyone wish to modify it even further, feel free to do so.

2 Likes

I’m a little surprised this works as well as it does, but then I realized you are likely lighting your scene with point lights. As strange as it sounds this technique should work great with point lights or spot lights, but not with the first directional light, or emissive parts of the model.

Usually for this kind of an effect to work you need a pass that writes to the depth but not any color. Then any subsequent passes of the same model can be rendered again with out writing to z depth and get the correct sorted depth. That first pass is, however, not guaranteed to render in the correct order, so you might get some surface doubling.

It’s working here because the way the standard shader already works is the first directional light (even if there isn’t one) and emissive color is rendered in a pass with z write on and all subsequent lights are rendered afterwards as transparent blend shaders, even when using “opaque” or “cutout”.

Actually, you might be surprised, but the model’s red stripes are 0.5 emissive parts.
Linear light also works the same way as spot lights even if I haven’t used any in the screenshots.
I tried it before posting the result with linear lights.

You’re right on the surface doubling, but I never wrote there weren’t any. This is where it gets interesting. The way the Standard shaders were already scripted seems to do the job in guaranteeing that the passes are done in the right order. That’s what surprised me the most as I was trying to modify the shader by doing some soft reverse-engineering with the shaders’ files you can get from the archives. The Standard shader is actually both complex and simple. You got the shader script which link the whole thing together, you got the C-Sharp script which controls what appear in the Editor GUI as well as the behavior from each options and you got 9 cginc files which includes all the possible snippets required to render each pass. When I was looking at those files, I noticed that the not only _ZWrite is already managed in every passes if it is active, but also that each pass are done in a specific order depending on what is required to render. Then I looked up until I found “where” the snippets were checking if it _ZWrite was active and that’s how I ended up modifying the C-Sharp script instead of the .cginc files.

What I’m getting at is that, unlike Fade or Transparent, due to how the Shader is already scripted, the pixel on each face actually get a priority making it that the face above with an alpha value always apply its RGB * alpha values before the face below. The best way I could describe it is that the alpha value of faces with lower Z-buffed returned value (closer to the camera/rendering source) always gets their value above the ones behind. The best part where this is useful is when you got a “solid” part as with the golden bracelet and the mask of the character I have shown.

It’s not perfect and there are many issues, but since those issues can easily be foresee, it’s still possible to work with it just fine. It’s, at least, a lot better for transparent mesh which involve both concave and opaque parts.

For example, some concave faces (from the transparent mesh itself) won’t appears through mesh while some other will. This is a problem that is present within the shader itself and is also part of the Fade and Transparent modes. To fix it, I will have to modify the default .cginc files but that’s for another time.
Another issue will be about the hardware. Blending alpha on top of using the dept-buffered for each pixel is a bit more taxing on the render. For something simple like the scene I go on the screenshot versus a scene where you see dozen of characters with that material… I must admit I’m not sure how far it can go until we get some performance issues.
I did notice a drop in performance of about 0.5%-2% between using this mode and Cutout.

As I previously wrote, it’s just the result of some test I did and it did reach a better result for me.
It might not for everyone, but well… sharing is free so. :smile:

Ah, I hoped it was gonna work for me. I have decals on a floor as separate object (Standard Shader - fade). And they are rendered sometimes above smoke (Particle - Additive).

Set a custom render queue on your materials for this, you know you always want them to render after opaque but before other transparency, so you should set their queue to 2501. You can do this via script or via the debug inspector.

1 Like

Fantastic, thank you.

I tried using this, it works great when I play my game in Unity, looks exactly how I was wanting… but when I build for Xcode, I get a bunch of warnings. It says something like ShaderGUI isn’t accessible from line 6:

  • using System;
  • using UnityEngine;
    • namespace UnityEditor
  • {
  • internal class StandardShaderGUI : ShaderGUI

And neither is MaterialProperty. MaterialProperty is listed a lot, and I get an error for every time it’s referenced.

Thanks @Max_Bol !
@daveinpublic and others: the script needs to be put into the Editor folder.

But…I was hesitant to create this script because I know the standard shader GUI changed in newer versions of Unity.
So, I just copied the relevant code for this in my own script, rather than trying to override the StandardShaderGUI code.
The important code, provided by Max_Bol, is:

  material.SetOverrideTag("RenderType","Transparent");
material.SetInt("_SrcBlend",(int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend",(int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite",1);
material.DisableKeyword("_ALPHATEST_ON");
material.EnableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue=3000;

Just putting this in my own code and calling it during Awake or Start does the trick.

Set the mode to Fade and add this code in Start is enough:
material.SetInt(“_ZWrite”,1);

1 Like