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

Question [built-in] SV_Depth not working with mirrors

Discussion in 'General Graphics' started by SunnySunshine, Sep 29, 2020.

  1. SunnySunshine

    SunnySunshine

    Joined:
    May 18, 2009
    Posts:
    974
    I have a shader that offsets pixel by a value using SV_Depth. This has been working great.

    However, I just discovered this shader does not work properly with mirror reflections, and I can't figure out why.

    Here's the shader in action (working):


    The sphere is the object with the shader applied to it. Here, I'm simply affecting the depth offset value for demonstration.

    Here are the objects when reflected in a mirror:


    As you can see, the sphere is being rendered as if behind, even though it's in front of the cube.

    Here's the depth offset shader:

    Code (CSharp):
    1. Shader "Unlit/Frag_TestDepth"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Texture", 2D) = "white" {}
    6.         _DepthOffset("DepthOffset", Float) = 0
    7.     }
    8.     SubShader
    9.     {
    10.         Tags { "RenderType"="Opaque" }
    11.         LOD 100
    12.  
    13.         Pass
    14.         {
    15.             CGPROGRAM
    16.             #pragma vertex vert
    17.             #pragma fragment frag
    18.  
    19.             #include "UnityCG.cginc"
    20.  
    21.             struct appdata
    22.             {
    23.                 float4 vertex : POSITION;
    24.                 float2 uv : TEXCOORD0;
    25.             };
    26.  
    27.             struct v2f
    28.             {
    29.                 float2 uv : TEXCOORD0;
    30.                 float4 vertex : SV_POSITION;
    31.                 float eyeDepth : TEXCOORD1;
    32.             };
    33.  
    34.             sampler2D _MainTex;
    35.             float4 _MainTex_ST;
    36.             float _DepthOffset;
    37.  
    38.             inline float LinearEyeDepthToOutDepth(float z)
    39.             {
    40.                 return (1 - _ZBufferParams.w * z) / (_ZBufferParams.z * z);
    41.             }
    42.  
    43.             v2f vert (appdata v)
    44.             {
    45.                 v2f o;
    46.                 o.vertex = UnityObjectToClipPos(v.vertex);
    47.                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    48.                 o.eyeDepth = -UnityObjectToViewPos(v.vertex.xyz).z;
    49.                 return o;
    50.             }
    51.  
    52.             //fixed4 frag (v2f i) : SV_Target
    53.             fixed4 frag (v2f i, out float pixelOffsetDepth : SV_Depth) : SV_Target
    54.             {
    55.                 float z = (i.eyeDepth + _DepthOffset);
    56.  
    57.                 float localLinearEyeDepthToOutDepth = LinearEyeDepthToOutDepth(z);
    58.                 pixelOffsetDepth = localLinearEyeDepthToOutDepth;
    59.  
    60.                 return saturate(float4(localLinearEyeDepthToOutDepth.xxx, 1));
    61.             }
    62.             ENDCG
    63.         }
    64.     }
    65. }
    66.  
    Fairly straight forward.

    The weird thing is - it doesn't seem to matter what value is written to SV_Depth. As soon as that value is being written, the mirror reflection won't work properly. If I don't write SV_Depth (for example changing "out float" to "in float"), the mirror will work as expected (but naturally the depth offset function is lost).

    The mirror script is taken from this:
    http://wiki.unity3d.com/index.php/MirrorReflection4

    The render texture (for the mirror) that these objects are being rendered into does have a depth buffer, so I'm not quite sure what's going on.

    So the question is - why doesn't writing to SV_Depth work for the mirror camera?

    Any pointer would be helpful, because I've tried everything I can think of!
     
    Last edited: Sep 29, 2020
  2. SunnySunshine

    SunnySunshine

    Joined:
    May 18, 2009
    Posts:
    974
    Revisiting this topic. Really would like to solve this but out of ideas.

    I attached a small sample project where you can see the problem.


    Sorry for summoning you so rudely @bgolus , but you've always been of such great help in the past!
     

    Attached Files:

  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    The
    _ZBufferParams
    values likely won't be valid for any camera with a custom projection matrix, like any mirror camera is going to use. You'll want to use a system that passes the view space position of the vertices to the fragment, offset the z, and then apply the current projection matrix to that to get the appropriate depth value.
     
    SunnySunshine likes this.