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

[5.6]How to use Material.SetShaderPassEnabled?

Discussion in 'General Graphics' started by colin299, Apr 16, 2017.

  1. colin299

    colin299

    Joined:
    Sep 2, 2013
    Posts:
    176
    Hello, I am writing a custom material editor,

    currently I can
    -toggle shader keywords on off
    -only show properties(float/texture/color)when a shader keyword is on

    but when I try to toggle a shader PASS on/off, I failed
    the material always render all passes in the shader.

    here is the code, wonder if I am doing something wrong.(see line 15,16 & 35)
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System;
    4. public class MyUberShader_CustomInspector : ShaderGUI
    5. {
    6.     Material targetMat;
    7.     public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
    8.     {
    9.         // render the default gui
    10.         base.OnGUI(materialEditor, properties);
    11.  
    12.         targetMat = materialEditor.target as Material;
    13.  
    14.         //toggle PASS ON/OFF not working :(
    15.         ShowToggle_ShaderPass("Colin/AllSharedPass/Edge/EDGE");
    16.         //ShowToggle_ShaderPass("EDGE"); //also not working
    17.  
    18.         //toggle keyword ON/OFF works :)
    19.         if (ShowToggle_ShaderKeyword("forceRED_ON"))
    20.         {
    21.             //show properties used by this keyword
    22.             //.......
    23.         }
    24.     }
    25.     bool ShowToggle_ShaderPass(string passName)
    26.     {
    27.         // see if pass is ON, and show a checkbox
    28.         bool isPassAlreadyToggleOn = targetMat.GetShaderPassEnabled(passName);
    29.         EditorGUI.BeginChangeCheck();
    30.         bool shouldPassToggleOnNow = EditorGUILayout.Toggle("toggle pass - " + passName + " ON?)", isPassAlreadyToggleOn);
    31.         if (EditorGUI.EndChangeCheck())
    32.         {
    33.             // enable or disable the shader pass based on new checkbox value
    34.             Debug.Log("Set pass " + passName + ": " + shouldPassToggleOnNow);
    35.             targetMat.SetShaderPassEnabled(passName, shouldPassToggleOnNow);  //toggle PASS ON/OFF not working :(
    36.         }
    37.         return shouldPassToggleOnNow;
    38.     }
    39.     bool ShowToggle_ShaderKeyword(string keyword)
    40.     {
    41.         // see if redify is set, and show a checkbox
    42.         bool redify = Array.IndexOf(targetMat.shaderKeywords, keyword) != -1;
    43.         EditorGUI.BeginChangeCheck();
    44.         redify = EditorGUILayout.Toggle("toggle keyword - " + keyword + " ON?", redify);
    45.         if (EditorGUI.EndChangeCheck())
    46.         {
    47.             // enable or disable the keyword based on checkbox
    48.             if (redify)
    49.                 targetMat.EnableKeyword(keyword);
    50.             else
    51.                 targetMat.DisableKeyword(keyword);
    52.         }
    53.         return redify;
    54.     }
    55. }
    56.  
    and here is the shader code
    Code (CSharp):
    1. Shader "Colin/MyUberShader"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Texture", 2D) = "white" {}
    6.     }
    7.     SubShader
    8.     {
    9.         Tags { "RenderType"="Opaque"}
    10.  
    11.         UsePass "Colin/AllSharedPass/SurfaceColor/SURFACECOLOR"
    12.         UsePass "Colin/AllSharedPass/Edge/EDGE"  
    13.     }
    14.     CustomEditor "MyUberShader_CustomInspector"
    15. }
    16.  
     
  2. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,240
    I made a fix for this but I think it's not due until 5.6.0p1. (I can't check to be sure right now)

    I recommend trying it in that version when it comes out, which is very soon, and post back here if it still doesn't work then.

    Regards,
     
    colin299 likes this.
  3. NoiseFloorDev

    NoiseFloorDev

    Joined:
    May 13, 2017
    Posts:
    104
    I still have this problem in 2017.1.0f3. Shader passes disabled with SetShaderPassEnabled still render.

    Now I see "Note that the Shader pass enable/disable flag only affects custom rendering pipelines that use the RenderLoop class" in the docs (this is missing in the class comments, which simply say "Enables or disables a Shader pass on a per-Material level"), but that doesn't make sense. Why can't we simply disable passes?
     
  4. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,240
    It should work in all rendering pipelines. I'm using it for the new particle standard shaders, which is why it got added to the non-custom rendering pipelines. You could submit a bug report if you have a case where it doesn't work.

    I will update the docs too.
     
  5. NoiseFloorDev

    NoiseFloorDev

    Joined:
    May 13, 2017
    Posts:
    104
    I can do that, but it doesn't work in any case for me, so maybe I'm doing something wrong. Just as a quick sanity check:

    In my shader I have

    Pass
    {
    Name "Main"
    }

    and I've disabled the shader with mat.SetShaderPassEnabled("Main", false) from a MaterialEditor. I see the pass name in the "Disabled Shader Passes" array in the debug view for the material. I also tried the full path, eg. "MyShader/Main" (which would make much more sense when using UsePass), but no luck there either.
     
  6. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,240
    Ah ok. For me, I use it like this:

    Shader:
    Code (CSharp):
    1. GrabPass
    2. {
    3.     Tags { "LightMode" = "Always" }
    4.     "_GrabTexture"
    5. }
    Script:
    Code (CSharp):
    1. material.SetShaderPassEnabled("Always", useDistortion);
    So I suspect it works on the "LightMode" tag rather than the actual name of the pass.

    EDIT: Yep. From the docs:
     
  7. NoiseFloorDev

    NoiseFloorDev

    Joined:
    May 13, 2017
    Posts:
    104
    Hmm, so it's just a poorly-named method. I could repurpose that tag (since this isn't a lit scene), but that seems like a bad idea. Hopefully we'll get a real way to control which passes are used, since that seems like a basic control.
     
  8. GarrettJohnson

    GarrettJohnson

    Joined:
    Jul 15, 2012
    Posts:
    1
    I know this is a bit of an old thread, but I thought I'd chime in -- that's a very confusingly named function, and the docs don't really do a lot to help. Even the argument name for the function is "passName" rather than "lightMode". This is further confused by the function "findPass()" also taking a "passName" (except it's actually the name of the pass).

    I'd been trying to use this for awhile and while I'd really prefer a function that allows for disabling / enabling by true pass name, this will work. Having two slightly more generic functions on a material like "SetPassTagEnabled(tagName, tagValue, enabled)" and "SetPassNameEnabled(passName, enabled)" would really be useful, though.

    Thanks!

    Edit: Turns out I actually can't do what I want with this function because the rendering engine looks for specific keywords in the LightMode.
     
    Last edited: Aug 20, 2017
  9. derrickMT

    derrickMT

    Joined:
    Apr 19, 2017
    Posts:
    2
    Would love to get a definitive answer on this as I haven't gotten it to work.

    I'm trying to make the ShadowCaster pass optional and toggle-able via a ShaderGUI checkbox. I can use:

    Code (CSharp):
    1. material.SetShaderPassEnabled("ShadowCaster", useShadows);
    And then query it via:

    Code (CSharp):
    1. material.GetShaderPassEnabled("ShadowCaster");
    And I get the expected result (true or false, depending on the checkbox) but in game the mesh is still always casting shadows regardless of the pass's enabled state.
     
  10. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,240
    Please share your shader with us too (or at least the relevant bits)

    Thanks,
     
  11. theteadrinker

    theteadrinker

    Joined:
    Jan 6, 2015
    Posts:
    5
    This feature seems broken, yes, it works for turning on and off LightMode "Always".
    However, the docs say:

    "For example, if the Shader has a "refraction" pass but you only want to enable it on Materials that have a refraction Texture assigned, pass "refraction" as passName and false for enabled for Materials without a refraction Texture assigned. Note that the Shader pass enable/disable flag only affects custom rendering pipelines that use the RenderLoop class (via RenderLoop.DrawRenderers or RenderLoop.DrawShadows)."

    I tried using the string "refraction", as "LightMode", "Name", "PassName". No success...
     
  12. DominoM

    DominoM

    Joined:
    Nov 24, 2016
    Posts:
    460
    I could be wrong as I've not experimented with scripted render loops (I used the "Always" pass for my outline pass), but I think the problem is in the documentation rather than the feature.

    "passName Shader pass name (case insensitive)." would be easier to understand as something like:
    "passName Render loop pass name (case insensitive)."

    So if you are using a scripted render loop with a "refraction" pass, you could use that name. If you are using the default render loop then you are limited to those passes. I'd guess it doesn't work on ShadowCaster because that pass is enabled or disabled per light depending on the light settings, so the manual setting gets ignored.
     
    Last edited: Oct 3, 2017
  13. jjxtra

    jjxtra

    Joined:
    Aug 30, 2013
    Posts:
    1,455
    Is this per material or per shader? Seems to apply to all my material even if I clone them...
     
  14. mherbold

    mherbold

    Joined:
    Jun 4, 2017
    Posts:
    35
    Any updates on this? I am trying to do what derrickMT is trying to do - enable / disable the shadow casting pass using material.SetShaderPassEnabled but it does not work, the shadow casting pass always runs. I tried both the pass name and the lightmode. Neither one works to shut off the pass for shadow casting. I think the shadow casting renderer does not care about whether the shadow casting pass is enabled or not.
     
  15. bluescrn

    bluescrn

    Joined:
    Feb 25, 2013
    Posts:
    629
    The documentation could really do with clarifying for this.

    It looks at first glance like SetShaderPassEnabled() was a method to enable/disable *named* passes programatically - for example, to enable/disable one or more overlaid VFX passes on a character shader*

    But nope, it doesn't seem to work like that at all... and there doesn't seem to be another method of programatically disabling/enabling a pass.

    (*perhaps in cases where you've already got rather too many multi_compiles and shader_features and don't want to add yet another....)
     
    Brad-Newman likes this.
  16. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    168
    +1 for this. Misleading documentation. And it would be far more useful in many cases for it it actually allow toggling named passes, as the method argument implies.
     
    Brad-Newman, tspk91 and bluescrn like this.
  17. Tudor

    Tudor

    Joined:
    Sep 27, 2012
    Posts:
    150
    So let me get this straight, in unity, you cannot disable shader passes. You can only change the `Tags { "LightMode" = "ForwardBase" }` to `Tags { "LightMode" = "ForwardAdd" }` etc. but not disable the pass or do anything based on the `Name "MYPASSNAME".

    So the only way to do this is to make 2 or 10 copies of your shader? If you want to save unnecessary passes? Goddamn
     
    EthanFischer, morepixels and tspk91 like this.
  18. Synergiance

    Synergiance

    Joined:
    Apr 10, 2018
    Posts:
    8
    Currently that is the workaround I'm using, which is why I have around 20 different shader files. It would be quite useful to be able to reduce this number by swapping passes.
     
  19. bitinn

    bitinn

    Joined:
    Aug 20, 2016
    Posts:
    958
    @richardkettlewell crazy question for an old thread:

    could you explain to me why this doesn't work?

    Code (CSharp):
    1. public class StandardShaderUI : ShaderGUI
    2. {
    3.     override public void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
    4.     {
    5.         base.OnGUI(materialEditor, properties);
    6.  
    7.         var target = materialEditor.target as Material;
    8.  
    9.         if (GUI.changed)
    10.         {
    11.             Debug.Log("Changed");
    12.             Debug.Log(target.GetFloat("_DebugDepthPass"));
    13.             target.SetShaderPassEnabled("ShadowCaster", target.GetFloat("_DebugDepthPass") < 0.5f);
    14.         }
    15.     }
    16. }
    I can detect the changes and I can see the float is properly set, and yet, ShadowCaster continue to be called when I look at Frame Debugger.

    What's wrong with my approach? Do I HAVE TO draw the toggle myself or something?

    (just to clarify I want the depth pass to be skipped, when debug flag is 1)

    (and again I made sure my ShadowCaster pass is actually using "LightMode" = "ShadowCaster")

    I desperately need an example somewhere that show me SetShaderPassEnabled actually works, and I know they work, so there must be some simple oversight on my part.
     
    Last edited: Apr 27, 2020
  20. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,240
    The script looks ok to me.

    We use this function in the standard particle shader, and it looks equivalent to your usage.
    If you have exhausted all options, you could report it as a bug.. even if it's your mistake, it should motivate someone to improve the docs page, as it's not really your fault if the docs are rubbish for this :(
     
  21. Suruin1

    Suruin1

    Joined:
    Aug 19, 2020
    Posts:
    1
    I upload my simple project about using SetShaderPassEnabled . I also can't open or close shadow by using material.SetShaderPassEnabled("ShadowCaster", useShadows). I try it on unity 2019.4 and 2020, but failed to get correct result on both versions.

    This project use built-in renderer pipleline, and the function SetShaderPassEnabled is in script ShadowON_OFF.cs.

    Please tell me how to open and close ShadowCaster pass in runtime.
     

    Attached Files:

  22. BOXOPHOBIC

    BOXOPHOBIC

    Joined:
    Jul 17, 2015
    Posts:
    481
    I was playing with SetShaderPassEnabled today trying to understand how it works :mad:
    And while at it, I noticed that ShadowCaster is actually SHADOWCASTER (urp 12).
    Hope it helps, not sure if this works...

    upload_2021-9-23_18-49-51.png
     
    Suruin1 likes this.
  23. cyberjoys

    cyberjoys

    Joined:
    Dec 1, 2020
    Posts:
    64
    definitely now working with ShadowCaster / SHADOWCASTER pass,
    also, would it not be nice if we could control per material pass enable/disable in command buffer which then can be scheduled into the render loop