Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Intersection Shader, cull front minus cull back?

Discussion in 'Shaders' started by spakment, Jun 19, 2018.

  1. spakment

    spakment

    Joined:
    Dec 19, 2017
    Posts:
    96
    I'm trying to create a shader which will ultimately create a greyscale mask for a (desaturate) post processing effect. I'm completely new to shaders so sorry about the huge gaps in my knowledge.
    This is my progress so far, I want just the bits in dark green.



    I'm doing 2 passes with ZTest Greater, the first pass with Cull Front (dark green) and then Cull Back (light green).
    How do I remove the (light green) pixels from rendering on the 2nd pass?

    I tried calling "discard;" but that didn't work.
    Please pick this to pieces if I'm doing it all wrong!

    Code (CSharp):
    1. Shader "Spakment/Intersect/TestShaderTwoPass"
    2. {
    3.     Properties
    4.     {
    5.         [HDR] _Color("Color", Color) = (1,1,1,1)
    6.         [HDR] _ColorTint("ColorTint", Color) = (1,1,1,1)
    7.     }
    8.     SubShader
    9.     {
    10.         Tags { "RenderType"="Transparent" "Queue" = "Geometry+10" }
    11.         LOD 100
    12.         ZWrite Off
    13.  
    14.         Pass
    15.         {
    16.             Cull Front
    17.             ZTest Greater
    18.             CGPROGRAM
    19.             #pragma vertex vert
    20.             #pragma fragment frag
    21.          
    22.             #include "UnityCG.cginc"
    23.  
    24.             struct appdata
    25.             {
    26.                 float4 vertex : POSITION;
    27.             };
    28.  
    29.             struct v2f
    30.             {
    31.                 float4 vertex : SV_POSITION;
    32.             };
    33.  
    34.  
    35.             float4 _Color;
    36.  
    37.             v2f vert (appdata v)
    38.             {
    39.                 v2f o;
    40.                 o.vertex = UnityObjectToClipPos(v.vertex);
    41.                 return o;
    42.             }
    43.             fixed4 frag (v2f i) : SV_Target
    44.             {
    45.                 return _Color;
    46.             }
    47.  
    48.          
    49.             ENDCG
    50.         }
    51.  
    52.  
    53.         Pass
    54.         {
    55.             Cull Back
    56.             ZTest Greater
    57.             CGPROGRAM
    58.             #pragma vertex vert
    59.             #pragma fragment frag
    60.          
    61.             #include "UnityCG.cginc"
    62.  
    63.             struct appdata
    64.             {
    65.                 float4 vertex : POSITION;
    66.             };
    67.  
    68.             struct v2f
    69.             {
    70.                 float4 vertex : SV_POSITION;
    71.             };
    72.  
    73.  
    74.             float4 _ColorTint;
    75.  
    76.  
    77.             v2f vert (appdata v)
    78.             {
    79.                 v2f o;
    80.                 o.vertex = UnityObjectToClipPos(v.vertex);
    81.                 return o;
    82.             }
    83.             fixed4 frag (v2f i) : SV_Target
    84.             {
    85.                 //discard;
    86.                 return _ColorTint;
    87.             }
    88.  
    89.          
    90.             ENDCG
    91.         }
    92.     }
    93. }
    94.  
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Just don't do the second pass?


    I'm guessing the issue is where the green pixels are you want the original image to remain untouched, and that second pass is hiding some dark green areas, correct? You should look into using stencils then. You'll want to do the "light green" pass first, but have it write to a stencil value, and use ColorMask 0 (which will prevent it from writing to the color, only to the depth and/or stencil buffers). Then render the "dark green" pass with a stencil test to only render where the first pass did not write.
     
  3. spakment

    spakment

    Joined:
    Dec 19, 2017
    Posts:
    96
    @bgolus - thank you for this, you were correct the light green was covering the dark green behind it.

    I had an idea I needed the stencil but the re-ordering of the passes was catching me out. I was confusing myself, your reply got me out of going down the wrong route.

    Also thanks for you responses on here https://forum.unity.com/threads/stencil-shader-with-depth.452575/ as they helped me out stop the stencil from other objects clashing with each other.

    It worked!


    This is the current working shader - does this seem a sensible (performant) way to achieve the stencil clearing?
    Not sure if there's any way to reduce down the 3 passes?

    Code (CSharp):
    1. Shader "Beanpug/Intersect/PassesWithStencil"
    2. {
    3.     Properties
    4.     {
    5.         [HDR] _Color("Color", Color) = (1,1,1,1)
    6.     }
    7.     SubShader
    8.     {
    9.         //Rendertype: Opaque, Transparent or Overlay all give same result...
    10.         //Queue is important here! Must be over 2500 to get front to back rendering, Overlay = 4000 (Transparent also works..)
    11.         Tags { "RenderType"="Opaque" "Queue" = "Overlay" }
    12.         LOD 100
    13.         ZWrite Off
    14.         //first pass sets the mask for the "front geometry"
    15.         Pass
    16.         {
    17.             Cull Back
    18.             ZTest Greater
    19.             ColorMask 0
    20.  
    21.             Stencil {
    22.                 Ref 1
    23.                 Comp Always
    24.                 Pass Replace
    25.             }
    26.  
    27.         }
    28.         //second pass turn off culling, could be Cull Off or Cull Front (both acheive the same thing)
    29.         //use the mask from the first pass and draw the color
    30.         Pass
    31.         {
    32.             Cull Off
    33.             ZTest Greater
    34.  
    35.             Stencil {
    36.                 Ref 1
    37.                 Comp NotEqual
    38.             }
    39.  
    40.             CGPROGRAM
    41.             #pragma vertex vert
    42.             #pragma fragment frag
    43.             #include "UnityCG.cginc"
    44.  
    45.             struct appdata
    46.             {
    47.                 float4 vertex : POSITION;
    48.             };
    49.  
    50.             struct v2f
    51.             {
    52.                 float4 vertex : SV_POSITION;
    53.             };
    54.  
    55.  
    56.             float4 _Color;
    57.  
    58.             v2f vert (appdata v)
    59.             {
    60.                 v2f o;
    61.                 o.vertex = UnityObjectToClipPos(v.vertex);
    62.                 return o;
    63.             }
    64.             fixed4 frag (v2f i) : SV_Target
    65.             {
    66.                 return _Color; // just return it
    67.             }
    68.             ENDCG
    69.         }
    70. // reset the stencil buffer so other objects dont mask out this one
    71.         Pass
    72.         {
    73.             //Cull Back
    74.             ZTest Greater
    75.             ColorMask 0
    76.  
    77.             Stencil {
    78.                 Ref 0
    79.                 Comp Always
    80.                 Pass Zero
    81.             }
    82.  
    83.         }
    84.     }
    85. }
    86.  
     
    Last edited: Jun 20, 2018
  4. Radivarig

    Radivarig

    Joined:
    May 15, 2013
    Posts:
    119
    Any ideas how to make it work in URP?
     
  5. april_4_short

    april_4_short

    Joined:
    Jul 19, 2021
    Posts:
    489
    As I understand it, anything that requires multiple passes is a bit of a problem in URP, or just impossible.
     
  6. Radivarig

    Radivarig

    Joined:
    May 15, 2013
    Posts:
    119
  7. april_4_short

    april_4_short

    Joined:
    Jul 19, 2021
    Posts:
    489
  8. Radivarig

    Radivarig

    Joined:
    May 15, 2013
    Posts:
    119
    Haha, yeah I get the feeling.

    Anyway I found this topic https://forum.unity.com/threads/lwr...ing-scriptablerenderpass.580498/#post-4524073

    which says that multiple passes are done with adding RenderObjects

    Also this issue tracker states it is "by design" to only render the first pass https://issuetracker.unity3d.com/is...s-gets-rendered-when-using-multi-pass-shaders
     
  9. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    The HDRP makes explicit use of multi-pass shaders for transparency, but it's a feature of that specific SRP which has multiple different
    "LightMode"
    passes that individually will only be rendered once.

    Multi-pass shaders like what's usually done for stencils with multiple unlit passes are explicitly not supported by either SRP. Render Objects aka Render Features have been pushed as "you use these now", but they're woefully insufficient for more complex setups you might need / want for things like stencils. Using multiple materials or multiple render components is unfortunately the only option left for the included SRPs when you need more fine control for when passes render / how they're sorted.
     
    april_4_short likes this.
  10. Radivarig

    Radivarig

    Joined:
    May 15, 2013
    Posts:
    119
  11. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Yes. You'd want to use a separate material per-pass. Though if that's the only thing you're trying to do, then Render Features can work too.
     
    Last edited: Aug 11, 2021
    Radivarig likes this.
  12. april_4_short

    april_4_short

    Joined:
    Jul 19, 2021
    Posts:
    489
    Without Vertex shaders?

    Sorry if this is a stupid question. The last time I looked at Shader Graph and SRPs, it seemed like vertex shaders weren't a thing in that world.
     
  13. lilacsky824

    lilacsky824

    Joined:
    May 19, 2018
    Posts:
    171
    It is not exposed as vertex and fragment stage in older version.
    Newer version of shader graph shows explictly like here's screenshot..
     
  14. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Shader Graph is just a vertex fragment shader generator. Almost all of Unity’s built in shaders for the SRPs are straight vertex fragment shaders and not Shader Graph based. There were a few in the past for the HDRP that started out as Shader Graphs that they’ve since converted to vertex fragment shaders.

    Because vertex fragment shaders are inherently more powerful and customizable. Shader Graph shaders can only do the narrow range of things they’ve been designed to support.
     
    Last edited: Aug 11, 2021
  15. ToxicTree

    ToxicTree

    Joined:
    Aug 22, 2021
    Posts:
    27
    Looking for a solution with shader graphs too when it comes to these intersections.

    I managed to get this result using custom shader lab code
    upload_2022-7-14_6-54-13.png

    Shader:

    Code (CSharp):
    1. Shader "Custom/Intersect/PassesWithStencil"
    2. {
    3.     Properties
    4.     {
    5.         [HDR] _Color("Color", Color) = (1,1,1,1)
    6.     }
    7.     SubShader
    8.     {
    9.         //Rendertype: Opaque, Transparent or Overlay all give same result...
    10.         //Queue is important here! Must be over 2500 to get front to back rendering, Overlay = 4000 (Transparent also works..)
    11.         Tags
    12.         {
    13.             "RenderType"="Opaque" "Queue" = "Overlay"
    14.         }
    15.         LOD 100
    16.         ZWrite Off
    17.         //first pass sets the mask for the "front geometry"
    18.         Pass
    19.         {
    20.             Cull Back
    21.             ZTest Greater
    22.             ColorMask 0
    23.  
    24.             Stencil
    25.             {
    26.                 Ref 1
    27.                 Comp Always
    28.                 Pass Replace
    29.             }
    30.  
    31.         }
    32.         //second pass turn off culling, could be Cull Off or Cull Front (both acheive the same thing)
    33.         //use the mask from the first pass and draw the color
    34.         Pass
    35.         {
    36.             Cull Off
    37.             ZTest Greater
    38.  
    39.             Stencil
    40.             {
    41.                 Ref 1
    42.                 Comp NotEqual
    43.             }
    44.  
    45.             CGPROGRAM
    46.             #pragma vertex vert
    47.             #pragma fragment frag
    48.             #include "UnityCG.cginc"
    49.  
    50.             struct appdata
    51.             {
    52.                 float4 vertex : POSITION;
    53.             };
    54.  
    55.             struct v2f
    56.             {
    57.                 float4 vertex : SV_POSITION;
    58.             };
    59.  
    60.  
    61.             float4 _Color;
    62.  
    63.             v2f vert(appdata v)
    64.             {
    65.                 v2f o;
    66.                 o.vertex = UnityObjectToClipPos(v.vertex);
    67.                 return o;
    68.             }
    69.  
    70.             fixed4 frag(v2f i) : SV_Target
    71.             {
    72.                 return _Color; // just return it
    73.             }
    74.             ENDCG
    75.         }
    76.         // reset the stencil buffer so other objects dont mask out this one
    77.         Pass
    78.         {
    79.             //Cull Back
    80.             ZTest Greater
    81.             ColorMask 0
    82.  
    83.             Stencil
    84.             {
    85.                 Ref 0
    86.                 Comp Always
    87.                 Pass Zero
    88.             }
    89.  
    90.         }
    91.     }
    92. }
    This is how far I've come using Universial Render Pipeline / URP:
    upload_2022-7-14_6-58-2.png

    Added 3 Rendering Features with various stencil and depth overrides to match the custom shader:
    upload_2022-7-14_7-0-40.png

    1: Depth on, Test Greater, Don't write, Stencil 1 Always Replace
    2. Depth on, Test Greater, Don't write, Stencil 1 Not Equal Keep
    3. Depth on, Test Greater, Don't write, Stencil 0 Always Zero

    I'm doing some experiments with culling in shader graph to maybe create several materials in case that is whats missing.
     
  16. ToxicTree

    ToxicTree

    Joined:
    Aug 22, 2021
    Posts:
    27
    Just got it working with multiple materials!

    upload_2022-7-14_7-53-29.png

    upload_2022-7-14_7-53-57.png

    Each pass in the custom shader code goes into a shader and being used by a material.
     
  17. ToxicTree

    ToxicTree

    Joined:
    Aug 22, 2021
    Posts:
    27
    However, that intersect_pass2 is tied up with the old shader code way of doing things because it needs Stencil.