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

How to make a shader for below/above ground rendering?

Discussion in 'Shaders' started by lowercase1024, Feb 9, 2021.

  1. lowercase1024

    lowercase1024

    Joined:
    Feb 5, 2021
    Posts:
    2
    I'm making AR app, where user can place a model (basically a mesh loaded from OBJ file) over a plane detected by AR. For better user experience, the app should render the part of the model below the plane with transparency, so that user can clearly see, whether the model is below/above the ground. Additionally, the AR plane itself should not be visible.

    I've been lurking this forum a lot and read Cg Programming/Unity/Outlining_Objects, to get more understanding of shaders and stencil buffer. And what I understood, is that the shader for AR plane should write to stencil buffer, while the model shader should check the buffer to determine how to render.

    But I still can't make it work properly. Here is what I've got so far.
    The ground plane shader writes stencil buffer and simply makes the plane transparent (alpha = 0):
    Code (CSharp):
    1. Shader "Plane"
    2. {
    3.     SubShader
    4.     {
    5.         Tags
    6.         {
    7.             "RenderType" = "Transparent"
    8.             "Queue" = "Transparent-10"
    9.         }
    10.         Pass
    11.         {
    12.             Cull Off
    13.             Blend SrcAlpha OneMinusSrcAlpha
    14.             Stencil {
    15.                 Ref 1
    16.                 Comp Always
    17.                 Pass Replace
    18.             }
    19.            
    20.             ZWrite On
    21.  
    22.             CGPROGRAM
    23.             #pragma vertex vert
    24.             #pragma fragment frag
    25.  
    26.             #include "UnityCG.cginc"
    27.  
    28.             struct v2f
    29.             {
    30.                 float4 pos : SV_POSITION;
    31.             };
    32.  
    33.             v2f vert(appdata_base v)
    34.             {
    35.                 v2f o;
    36.                 o.pos = UnityObjectToClipPos(v.vertex);
    37.                 return o;
    38.             }
    39.  
    40.             half4 frag(v2f i) : COLOR
    41.             {
    42.                 return float4(1.0, 1.0, 1.0, 0.0);
    43.             }
    44.             ENDCG
    45.         }
    46.     }
    47. }
    The model shader should make the part of the model below the plane 50% transparent, the part above the plane opaque. For this reason the shader has a two passes. The first pass handles the part of the model below the plane, that is, the transparent part. The second pass handles the part of the model above the plane, that is, the opaque part.
    Code (CSharp):
    1. Shader "Model"
    2. {
    3.     SubShader
    4.     {
    5.         Tags
    6.         {
    7.             "RenderType" = "Transparent"
    8.             "Queue" = "Transparent"
    9.         }
    10.         Pass
    11.         {
    12.             Blend SrcAlpha OneMinusSrcAlpha
    13.             Stencil
    14.             {
    15.                 Ref 1
    16.                 Comp Equal
    17.                 Pass Keep
    18.             }
    19.             ZTest Always
    20.  
    21.             CGPROGRAM
    22.             #pragma vertex vert
    23.             #pragma fragment frag
    24.  
    25.             float4 vert(float4 vertexPos : POSITION) : SV_POSITION
    26.             {
    27.                 return UnityObjectToClipPos(vertexPos);
    28.             }
    29.  
    30.             float4 frag(void) : COLOR
    31.             {
    32.                 return float4(0.0, 1.0, 0.0, 0.5);
    33.             }
    34.  
    35.             ENDCG
    36.         }
    37.         Pass
    38.         {
    39.             Stencil
    40.             {
    41.                 Ref 1
    42.                 Comp NotEqual
    43.                 Pass Keep
    44.             }
    45.  
    46.             CGPROGRAM
    47.             #pragma vertex vert
    48.             #pragma fragment frag
    49.  
    50.             float4 vert(float4 vertexPos : POSITION) : SV_POSITION
    51.             {
    52.                 return UnityObjectToClipPos(vertexPos);
    53.             }
    54.  
    55.             float4 frag(void) : COLOR
    56.             {
    57.                 return float4(0.0, 1.0, 0.0, 1);
    58.             }
    59.  
    60.             ENDCG
    61.         }
    62.     }
    63. }
    Here is how it looks:
    upload_2021-2-9_17-59-3.png upload_2021-2-9_17-59-44.png
    The plane cuts the cube by half horizontally, e.g. they both have pivot 0.5, 0.5, 0.5 and position 0, 0, 0).

    As I understand, I made a typical "see through walls", but I rather need the model to be cut by the AR plane into two parts: transparent (below the plane) and opaque (above the plane).

    I'm starting to think, that stencil is not really fits here. Should it be done based on ZWrite/ZTest somehow?
    Can anyone help me with this or point what to read?
     
  2. jamespaterson

    jamespaterson

    Joined:
    Jun 19, 2018
    Posts:
    395
    hi. just a suggestion for a different approach. Have you considered just providing the coordinates of the plane as parameters to the shader (this can be encoded as e.g. two vectors, XYZ for the center and XYZ for the normal to the plane), then in the shader working out the plane-relative coordinate of the fragment being rendered and deciding opacity there? This would only require one pass and no messing about with the stencil buffers etc
     
    lowercase1024 likes this.
  3. lowercase1024

    lowercase1024

    Joined:
    Feb 5, 2021
    Posts:
    2
    That might work for me, because I was thing about making a fake plane with the same normal and at the same position as the original, but much larger than the original one, found by AR to make it work when the model is bigger than the plane.
    Thanks!
     
    jamespaterson likes this.