Search Unity

Question How to add a pass tag to a ShaderGraph?

Discussion in 'Shader Graph' started by Bip901, Apr 11, 2020.

  1. Bip901

    Bip901

    Joined:
    May 18, 2017
    Posts:
    71
    In regular shaders, you can add pass tags like so:

    Tags { "LightMode" = "MyCustomPass" }

    How do you add them in ShaderGraph? I'm using URP (Universal Render Pipeline). I created a custom render pass. I want my shader to be drawn on that pass, so I need to tag it.
     
  2. alexanderameye

    alexanderameye

    Joined:
    Nov 27, 2013
    Posts:
    1,383
    You can't.

    But based on what you want to achieve there might be other methods? I've wanted to do this as well for one of my projects but did something else in the end that solved it.
     
  3. Bip901

    Bip901

    Joined:
    May 18, 2017
    Posts:
    71
    I ended up rewriting the ShaderGraph as a regular shader. What was your workaround?
     
  4. alexanderameye

    alexanderameye

    Joined:
    Nov 27, 2013
    Posts:
    1,383
    I wanted some shaders with a specific tag write to a render texture. What I do now is right before I render to the texture, I enable a global keyword that changes the output of the shader graph, and then I disable the keyword again after I rendered to the texture.
     
  5. BasicallyGames

    BasicallyGames

    Joined:
    Aug 31, 2018
    Posts:
    91
    Surely there's a way to do this? I just want to add "DisableBatching" = "True" to my sprite shader. That's it. I just want to disable sprite batching.

    Edit: Figured it out. If you right click the master node, you can generate the shader code. Save that as a shader and then you can add any tags you want to it.
     
    Last edited: Aug 20, 2020
    Bip901 likes this.
  6. Bip901

    Bip901

    Joined:
    May 18, 2017
    Posts:
    71
    Good to know. At the end of the day, no visual editor can replace raw code.
     
  7. RChrispy

    RChrispy

    Joined:
    Dec 18, 2013
    Posts:
    71
  8. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    289
    I periodically google to see if this has been added yet but it seems it still isn't the case. This thread comes up, so I'll put this info here incase others find it useful.

    In the mean time, if you really need to add a custom pass to a shader graph, a workaround is to create a second shader and UsePass to pull the passes from your shader graph into your second shader. I do this in ProPixelizer to add some custom outline passes like so:

    Code (csharp):
    1.  
    2.         SubShader
    3.         {
    4.             Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }
    5.  
    6.             UsePass "ProPixelizer/Hidden/ProPixelizerBase/UNIVERSAL FORWARD"
    7.             UsePass "ProPixelizer/Hidden/ProPixelizerBase/SHADOWCASTER"
    8.             UsePass "ProPixelizer/Hidden/ProPixelizerBase/DEPTHONLY"
    9.  
    10.         Pass
    11.         {
    12.             Name "ProPixelizerPass"
    13.             Tags {
    14.                 "RenderPipeline" = "UniversalRenderPipeline"
    15.                 "LightMode" = "ProPixelizer"
    16.                 "DisableBatching" = "True"
    17.             }
    18.  
    19. ... add your custom pass as normal here
    20.  
    This works, but it is a bit clunky. For instance, if you change the shader graph, Unity won't know it has to recompile your shader that inherits the passes, so you have to manually reimport it or re-save it to trigger a recompile. Also, you either have to disable the SRP batcher, or be very careful that your UnityPerMaterial CBUFFER matches that generated by the shadergraph (otherwise the SRP batcher will produce many graphical errors).
     
  9. alexanderameye

    alexanderameye

    Joined:
    Nov 27, 2013
    Posts:
    1,383
    Clunky indeed but thanks a lot for sharing, it seems like a good way to solve an issue I'm having. When you use UsePass like that (new to me) you would put the properties that are defined in the shadergraph in the non-shadergraph shader as well? Or how does that work then?

    I would think the shader would pull in the properties of the child passes but that does not seem the case. So my question is, where do you edit the properties that are defined in the shader-graph shader now?

    The CBUFFER stuff worries me as well.

    Edit
    It seems I can just redefine the properties in the non-shadergraph shader? What is the recommended way then to handle the CBUFFER? All seems to work if I just copy over the properties from the generate shadergraph to the handwritten shader.

    Also as an additional note, my workaround for working with these additional passes was to enable/disable a keyword in the Execute method of a custom pass. Then I could just stay in shadergraph, and branch based on the keyword. No idea about the performance but it did work well.
     
    Last edited: May 10, 2022
  10. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    289
    You do have to define the properties in the non-SG shader, like you say. For the CBUFFER stuff, I just copy that from the ShaderGraph as you did and it seems to work fine. If you need any properties that are only used in your custom pass, you'll need to add them to the shadergraph so that the CBUFFER blocks are the same for both.
     
  11. CosmicWorker

    CosmicWorker

    Joined:
    Jan 31, 2015
    Posts:
    3
    Found this topic while searching for any info on how to fix the shader warning "The shader of this material does not support skybox rendering" when using a custom skybox shader made with shadergraph.

    In shader graph's blackboard, click [ + ] > [ Keyword ] > [ Enum ].
    I've added keyword "RenderType" with a default value of "Background". This adds a shader tag "RenderType"="Background" which removes the warning.

    Hope this is the right solution and as intended by Unity.
     
    tomekkie2 likes this.
  12. tomekkie2

    tomekkie2

    Joined:
    Jul 6, 2012
    Posts:
    973
    I am making a selective URP ScriptableRenderFeature, supposed to work only on a number of custom shaders. Some of these are hlsl and some shader graphs.
    If I could use custom shader tags inside List<ShaderTagId> I could just select objects by custom shaders without the layermask setup.
    It would simplify the SRF setup, skipping just one step.
    I have tried to add a LightMode keyword with a custom enum value to shader graph, but unfortunately this did not work for me, so I am going to stay with the layermask selection.
    On the other hand I fear using methods by @ElliotB or @alexanderameye might overcomplicate the issue in my case.
     
    Last edited: Apr 28, 2023
  13. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    289
    As this thread still comes up on search, I came to add another solution. Rather than making use of UsePass to import a pass from your shadergraph into a shaderlab shader, you can add a pass to a ShaderGraph directly by implementing a ShaderGraph SubTarget (as in this thread).

    I'd be interested to hear what you are doing here that doesn't work. Your ShaderGraph will have a target matching your render pipeline, e.g. UniversalTarget, and a bunch of SubTargets the graph can use. Check, for example, the source for the UniversalLitSubTarget here. In particular, you want the SubShaders class, defining the SubShader program for this SubTarget, and in this method you can see all the passes being added. You could very easily modify the lightMode tag from these passes, and it will come up in the generated shader (a starting point might be to just copy and paste the LitSubTarget, or whichever one you want, and change the line below).

    Code (CSharp):
    1.             public static PassDescriptor Forward(
    2.                 UniversalTarget target,
    3.                 WorkflowMode workflowMode,
    4.                 bool blendModePreserveSpecular,
    5.                 PragmaCollection pragmas,
    6.                 KeywordCollection keywords)
    7.             {
    8.                 var result = new PassDescriptor()
    9.                 {
    10.                     // Definition
    11.                     displayName = "Universal Forward",
    12.                     referenceName = "SHADERPASS_FORWARD",
    13.                     lightMode = "UniversalForward", // <-- here
    14.                     useInPreview = true,
    15.                     ...
     
    Nintendo-Silence and tomekkie2 like this.
  14. tomekkie2

    tomekkie2

    Joined:
    Jul 6, 2012
    Posts:
    973
    Sounds interesting.
    But does that mean repeating the package embedding for every URP update?
     
  15. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    289
    You can avoid this to some extent by invoking these private helper methods via reflection:

    Code (CSharp):
    1. #region SubShader
    2.         static class SubShaders
    3.         {
    4.             public static SubShaderDescriptor ProPixelizerSubShader(UniversalTarget target, string renderType, string renderQueue, string disableBatchingTag)
    5.             {
    6.                 // Eurgh - why is everything private!
    7.                 // Use reflection to create a SubShader using the UniversalLitSubTarget as inspiration.
    8.                 var name = typeof(UniversalLitSubTarget).FullName + "+SubShaders," + typeof(UniversalLitSubTarget).Assembly.FullName;
    9.                 Type type = Type.GetType(name);
    10.                 MethodInfo method = type.GetMethod("LitSubShader", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
    11.                 var ssd = (SubShaderDescriptor)method.Invoke(null, new object[] { target, WorkflowMode.Specular, renderType, renderQueue, disableBatchingTag, false, false });
    12.  
    13.                 // Add an additional pass
    14.                 ssd.passes.Add(Passes.ProPixelizerMetadata(target, CoreBlockMasks.Vertex, CoreBlockMasks.FragmentAlphaOnly, CorePragmas.Forward, CoreKeywords.ShadowCaster));
    15.  
    16.                 // You can enumerate through the passes and modify them here
    17.                 var newPasses = new PassCollection();
    18.                 foreach (var originalPass in ssd.passes)
    19.                 {
    20.                     var pass = originalPass.descriptor;
    21.                     switch (pass.referenceName)
    22.                     {
    23.                         case "SHADERPASS_FORWARD":
    24.                             // we could change the includes to redirect to a different lighting calc, change lightmode, etc...
    25.                             break;
    26.                     }
    27.                     newPasses.Add(pass);
    28.                 }
    29.                 ssd.passes = newPasses;
    30.                 return ssd;
    31.             }
    32.         }
    33.         #endregion
    It would be much much nicer if these methods weren't private and we could use them 'the right way', but this works for now.

    EDIT: Slightly misunderstood your question - yes, you need to embed the package each update, which is also annoying! But you could probably automate that step. I might write something to do that for ProPixelizer, I'll post here if I do.
     
  16. Reanimate_L

    Reanimate_L

    Joined:
    Oct 10, 2009
    Posts:
    2,788
    Dude, your comment just help me trying to create custom render pass and keeping it compatible with SRP batcher. Thanks for the pointer man

    EDIT: Dang. . . it seems this method doesn't work anymore on URP 14++, in build all the shader just goes pink :/ welp
     
    Last edited: Jul 17, 2023
  17. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    289
    Which version of Unity were you using? I last tested it in 2022.3.1f1 and it still worked for me
     
  18. Reanimate_L

    Reanimate_L

    Joined:
    Oct 10, 2009
    Posts:
    2,788
    i'm on 2022.3.4 it's always give me broken shader on build somehow
     
    ElliotB likes this.
  19. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    289
    I tested in 2022.3.5 just now and its working (I dont have 2022.3.4 installed)
     
  20. Reanimate_L

    Reanimate_L

    Joined:
    Oct 10, 2009
    Posts:
    2,788
    i see, i'll test it out on 2022.3.5