Search Unity

StencilBuffer and depth testing

Discussion in 'Shaders' started by unity_0ulzZ5i1hY4lQw, Dec 18, 2019.

  1. unity_0ulzZ5i1hY4lQw

    unity_0ulzZ5i1hY4lQw

    Joined:
    Mar 15, 2018
    Posts:
    6
    Hello

    I'm trying to hide an object with a plane using a stencil buffer
    But I have a problem rendering an pixel of object only if the plane is in front of that pixel.

    the sphere is 1 on Z axis and plane is 0 on Z axis
    upload_2019-12-18_10-46-33.png

    the sphere is 1 on Z axis and plane is 10 on Z axis
    upload_2019-12-18_10-47-23.png
     
  2. Gufetto

    Gufetto

    Joined:
    Oct 19, 2015
    Posts:
    29
    Not sure if there is a better way to do it, but I came up with this. Still has some problems with depth testing in some cases, but does what you need, should be a good starting point.


    This one goes on the plane

    Code (CSharp):
    1. Shader "Custom/Occluder"
    2. {
    3.     Properties
    4.     {
    5.      
    6.     }
    7.     SubShader
    8.     {
    9.         Tags { "Queue" = "AlphaTest+1" }
    10.         Pass
    11.         {
    12.             Offset -1, -1
    13.             ZTest LEqual
    14.             ZWrite On
    15.             ColorMask 0
    16.             Cull off
    17.             Stencil
    18.             {
    19.                 Ref 50
    20.                 Comp Always
    21.                 Pass replace
    22.             }
    23.  
    24.         }
    25.     }
    26.  
    27. }
    28.  

    This one goes on the sphere

    Code (CSharp):
    1. Shader "Custom/Occluded"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Texture", 2D) = "white" {}
    6.     }
    7.  
    8.     SubShader
    9.     {
    10.         Tags {
    11.             "RenderType"="Opaque"
    12.             "Queue" = "AlphaTest+2"
    13.         }
    14.         LOD 100
    15.  
    16.  
    17.         Pass
    18.         {
    19.             Offset -1, -1
    20.             ZTest Greater
    21.             ZWrite On
    22.             Cull Off
    23.             Stencil
    24.             {
    25.                 Ref 50
    26.                 Comp Equal
    27.                 //ZFail zero
    28.             }
    29.  
    30.             CGPROGRAM
    31.             #pragma vertex vert
    32.             #pragma fragment frag
    33.             // make fog work
    34.             #pragma multi_compile_fog
    35.  
    36.             #include "UnityCG.cginc"
    37.  
    38.             struct appdata
    39.             {
    40.                 float4 vertex : POSITION;
    41.                 float2 uv : TEXCOORD0;
    42.             };
    43.  
    44.             struct v2f
    45.             {
    46.                 float2 uv : TEXCOORD0;
    47.                 UNITY_FOG_COORDS(1)
    48.                 float4 vertex : SV_POSITION;
    49.             };
    50.  
    51.             sampler2D _MainTex;
    52.             float4 _MainTex_ST;
    53.  
    54.             v2f vert (appdata v)
    55.             {
    56.                 v2f o;
    57.                 o.vertex = UnityObjectToClipPos(v.vertex);
    58.                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    59.                 UNITY_TRANSFER_FOG(o,o.vertex);
    60.                 return o;
    61.             }
    62.  
    63.             fixed4 frag (v2f i) : SV_Target
    64.             {
    65.                 // sample the texture
    66.                 fixed4 col = tex2D(_MainTex, i.uv);
    67.                 // apply fog
    68.                 UNITY_APPLY_FOG(i.fogCoord, col);
    69.                 return col;
    70.             }
    71.             ENDCG
    72.         }
    73.     }
    74. }
    75.  
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Working as intended. Stencils are explicitly only a 2D screen space thing and do not know about depth. There is no way to exclude objects that are closer to the camera than the plane but still allow objects that are further away purely using stencils.

    Ideally this could be partially solved with render order. Opaque queue objects already render front to back (closest to furthest). If objects that are masked by the stencil render before the stencil plane is rendered, the stencil buffer won't be marked and thus those objects won't render. So if you make both the plane and the masked objects all use the same queue it can work... if Unity was consistent about render order which it is not. Unity will often render multiple opaque objects using the same material together for better CPU side rendering efficiency at the cost of not maintaining the perfect front to back render order. Even if it was perfect it also won't handle the case where a masked object intersects with the plane.

    The only "perfect" solution is to use a customs shader that clips your meshes manually.
    https://forum.unity.com/threads/can...depth-for-stencil-shader.769175/#post-5124533

    Or use a render texture approach.
     
  4. dfkan12

    dfkan12

    Joined:
    Nov 1, 2017
    Posts:
    15
    Hej, Clip() seems to be expensive on mobile android, any other alternatives for this on quest?
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Nope.