1. Help us improve the editor usability and artist workflows. Join our discussion to provide your feedback.
    Dismiss Notice
  2. We're looking for feedback on Unity Starter Kits! Let us know what you’d like.
    Dismiss Notice
  3. We’re giving 2017.1 beta testers a chance to win t-shirts and a Nintendo Switch. Read more on the blog.
    Dismiss Notice
  4. Unity 2017.1 beta is now available for download.
    Dismiss Notice
  5. Unity 5.6 is now released.
    Dismiss Notice
  6. Get further faster with the Unity Plus Accelerator Pack, free for new Unity Plus subscribers for a limited time. Click here for more details.
    Dismiss Notice
  7. Check out all the fixes for 5.6 on the patch releases page.
    Dismiss Notice
  8. Learn how you'll soon be able to publish your games to China in four simple steps with Xiaomi. Sign up now for early access.
    Dismiss Notice

Standard material shader ignoring SetFloat property "_Mode"?

Discussion in 'Shaders' started by Hotdug, Jul 30, 2015.

  1. Hotdug


    Jul 3, 2014
    In my code I create a texture and fill it with colors (some are 100% transparent, others are 100% opaque). I then create a material and put the texture in it. Finally a quad is created and the material is used on its renderer.

    Code (csharp):
    1.       Color32[] colors = ...  //length: 250000
    3.       Texture2D t = new Texture2D(500, 500, TextureFormat.ARGB32, false);
    4.       t.SetPixels32(colors);
    5.       t.Apply();
    7.       Material mat = new Material(Shader.Find("Standard"));
    8.       mat.SetFloat("_Mode", 2);
    9.       mat.mainTexture = t;
    11.       GameObject go = GameObject.CreatePrimitive(PrimitiveType.Quad);
    12.       go.transform.localScale = new Vector3(500, 500, 1);
    13.       go.GetComponent<MeshRenderer>().material = mat;
    The problem is that alpha is ignored, all colors are 100% opaque. If I select the quad while playing I can see the properties of the material in Unity's inspector. Shader is "Standard" and the Rendering Mode is indeed "Fade".

    If I manually select "Fade" again from the drop down menu the transparent pixels in the texture immediately become transparent. If I set the inspector to Debug and manually go to Saved Properties > Floats > Element 10 (which is "_Mode") I can see that "Second" is indeed set to "2" (which means "Fade"). If I manually change this number to 1 ("Cutout") nothing happens. If I manually set it back to 2 nothing happens as well, all pixels remain opaque and alpha is still ignored.

    If I set it to 3 (for "Transparent") nothing happens. If I then change the inspector back to "Normal" still nothing happens, except that the Material's Rendering Mode shows as "Transparent" in the Inspector. If I then click the drop down list and select the already-selected "Transparent" option again *then* the alpha values are respected and some colors in the texture becomes non-opaque.

    Is this a bug or is something weird required when using SetFloat?

    Because SetFloat("_Mode", 2); does not work on the Standard shader. It seems like we can't use the Standard shader as intended from script.
  2. Thomas-Mountainborn


    Jun 11, 2015
  3. Farfarer


    Aug 17, 2010
    It's much easier to call the method in the shader's custom GUI, which will set all that up properly.

    Code (csharp):
    1. //Material material < this assumes you have a reference to the material already set.
    2. StandardShaderGUI.SetupMaterialWithBlendMode (material, StandardShaderGUI.BlendMode.Fade);
    Thomas-Mountainborn likes this.
  4. Thomas-Mountainborn


    Jun 11, 2015
    Oh, that's very handy indeed, I was unaware of its existence.
  5. Hotdug


    Jul 3, 2014
    "The name `StandardShaderGUI' does not exist in the current context"

    No results.

    Googling "StandardShaderGUI" gets strange results. It's like it doesn't exist or aren't supposed to be used in released games.

    Unfortunately your reply doesn't make sense. Do I need to import something weird? Why isn't this feature built into the Material class in the first place? I'm far from the only guy having trouble with this and from what I've read many other also think this is a bug.

    This works but frankly it feels like a joke that all of those lines are required just to get a standard shader that support transparency. Unity should do something about this.

    Putting the code here for anyone finding this thread in their search of making sense out of _Mode not working:

    Code (csharp):
    1. Material m = new Material(Shader.Find("Standard"));
    2. m.SetFloat("_Mode", 2);
    3. m.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
    4. m.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
    5. m.SetInt("_ZWrite", 0);
    6. m.DisableKeyword("_ALPHATEST_ON");
    7. m.EnableKeyword("_ALPHABLEND_ON");
    8. m.DisableKeyword("_ALPHAPREMULTIPLY_ON");
    9. m.renderQueue = 3000;
  6. Thomas-Mountainborn


    Jun 11, 2015
    The alternative is having a material with the mode you require set up in the inspector, and then copy that material to create the materials you need at runtime (using Instantiate(), not new Material(sourceMaterial)).

    You could also define an extension method to make your life a bit easier.

    Code (CSharp):
    1. public static class Extensions
    2. {
    3.     public static void SetAsFade(this Material material)
    4.     {
    5.         material.SetFloat("_Mode", 2);
    6.         material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
    7.         material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
    8.         material.SetInt("_ZWrite", 0);
    9.         material.DisableKeyword("_ALPHATEST_ON");
    10.         material.EnableKeyword("_ALPHABLEND_ON");
    11.         material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
    12.         material.renderQueue = 3000;
    13.     }
    14. }
    Then you can just do the following:

    Code (CSharp):
    1. Material mat = new Material(Shader.Find("Standard");
    2. mat.SetAsFade();
    Last edited: Jul 31, 2015
    vicator likes this.
  7. Farfarer


    Aug 17, 2010
    My bad, the StandardShaderGUI is part of the built-in shader code. You can get it from there, though.

    Code (csharp):
    2.     public enum BlendMode
    3.     {
    4.         Opaque,
    5.         Cutout,
    6.         Fade,        // Old school alpha-blending mode, fresnel does not affect amount of transparency
    7.         Transparent // Physically plausible transparency mode, implemented as alpha pre-multiply
    8.     }
    10.     public void SetupMaterialWithBlendMode(Material material, BlendMode blendMode)
    11.     {
    12.         switch (blendMode)
    13.         {
    14.             case BlendMode.Opaque:
    15.                 material.SetOverrideTag("RenderType", "");
    16.                 material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
    17.                 material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
    18.                 material.SetInt("_ZWrite", 1);
    19.                 material.DisableKeyword("_ALPHATEST_ON");
    20.                 material.DisableKeyword("_ALPHABLEND_ON");
    21.                 material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
    22.                 material.renderQueue = -1;
    23.                 break;
    24.             case BlendMode.Cutout:
    25.                 material.SetOverrideTag("RenderType", "TransparentCutout");
    26.                 material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
    27.                 material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
    28.                 material.SetInt("_ZWrite", 1);
    29.                 material.EnableKeyword("_ALPHATEST_ON");
    30.                 material.DisableKeyword("_ALPHABLEND_ON");
    31.                 material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
    32.                 material.renderQueue = 2450;
    33.                 break;
    34.             case BlendMode.Fade:
    35.                 material.SetOverrideTag("RenderType", "Transparent");
    36.                 material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
    37.                 material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
    38.                 material.SetInt("_ZWrite", 0);
    39.                 material.DisableKeyword("_ALPHATEST_ON");
    40.                 material.EnableKeyword("_ALPHABLEND_ON");
    41.                 material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
    42.                 material.renderQueue = 3000;
    43.                 break;
    44.             case BlendMode.Transparent:
    45.                 material.SetOverrideTag("RenderType", "Transparent");
    46.                 material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
    47.                 material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
    48.                 material.SetInt("_ZWrite", 0);
    49.                 material.DisableKeyword("_ALPHATEST_ON");
    50.                 material.DisableKeyword("_ALPHABLEND_ON");
    51.                 material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
    52.                 material.renderQueue = 3000;
    53.                 break;
    54.         }
    55.     }
    aheydeck likes this.
  8. aheydeck


    Dec 17, 2014
    It took me a full day to finally find this post, but it has eased my headache! Thank you! =)
  9. JohnRossitter


    Dec 18, 2013
    So, Im dealing with this now too.
    Strange thing for me is that it works in editor based code.
    But if I run in in a compiled version it does not....how does that make sense?
  10. Thomas-Mountainborn


    Jun 11, 2015
    In a packaged build, Unity will leave out any shader variants which are not used in any scene, since it believes it would be wasted space otherwise. You need to add an object which uses a material with the required mode to a scene .