Search Unity

Question Depth Texture on Objects/Materials

Discussion in 'Shaders' started by frankdervoelker, May 21, 2023.

  1. frankdervoelker

    frankdervoelker

    Joined:
    Nov 16, 2020
    Posts:
    11
    Hey guys.

    I am trying to write a depthmap shader. It works fine when I add this as post processing effect for the whole scene/camera. But when I add this shader to a single object/material it is no longer working.

    What I want to achieve is having a material/shader on an object in my scene and the object becomes darker (or lighter) the further away I move from this object.

    Maybe the _CameraDepthTexture is not working for single objects or some minor code changes?

    Code (CSharp):
    1. Shader "Custom/DepthShader"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Texture", 2D) = "white" {}
    6.     }
    7.     SubShader
    8.     {
    9.         Tags { "RenderType"="Opaque" }
    10.         LOD 100
    11.  
    12.         Pass
    13.         {
    14.             CGPROGRAM
    15.             #pragma vertex vert
    16.             #pragma fragment frag
    17.  
    18.             #include "UnityCG.cginc"
    19.  
    20.             struct appdata
    21.             {
    22.                 float4 pos : POSITION;
    23.                 float2 uv : TEXCOORD0;
    24.             };
    25.  
    26.             struct v2f
    27.             {
    28.                 half2 uv : TEXCOORD0;
    29.                 float4 pos : SV_POSITION;
    30.             };
    31.  
    32.             sampler2D _MainTex;
    33.             uniform sampler2D_float _CameraDepthTexture;
    34.             float _Intensity;
    35.             float4 _OverlayColor;
    36.  
    37.             v2f vert (appdata v)
    38.             {
    39.                 v2f o;
    40.                 o.pos = UnityObjectToClipPos (v.pos);
    41.                 o.uv = MultiplyUV(UNITY_MATRIX_TEXTURE0, v.uv);
    42.                 return o;
    43.             }
    44.  
    45.             fixed4 frag (v2f i) : SV_Target
    46.             {
    47.                 float depth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, i.uv));
    48.                 depth = pow(Linear01Depth(depth), .85);
    49.  
    50.  
    51.                 // sample the texture
    52.                 fixed4 col = tex2D(_MainTex, i.uv);
    53.                 col.rgb *= depth;
    54.                
    55.                 return col;
    56.             }
    57.             ENDCG
    58.         }
    59.     }
    60. }
    61.  
    upload_2023-5-21_18-13-28.png
     
  2. wwWwwwW1

    wwWwwwW1

    Joined:
    Oct 31, 2021
    Posts:
    767
    Hi, the depth texture is usually copied from camera depth buffer after opaque rendering for better performance.

    There're two solutions to make it available for your custom shader.
    • Change the render type to transparent in your custom shader.
    • Set the depth texture mode to "Force Prepass" to access _CameraDepthTexture during opaque rendering.
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    If it's on an existing object in the scene, you don't need to read the depth texture at all. You can just use the depth value the object itself already knows.

    This should give you the exact same results you got with the post process when placed on a mesh in the scene.
    depth = pow(Linear01Depth(i.pos.z), .85);
     
    wwWwwwW1 likes this.
  4. frankdervoelker

    frankdervoelker

    Joined:
    Nov 16, 2020
    Posts:
    11
    thx this was a valid solution. somehow the depth-texture approach doesn't work at all for me

    what also worked for me was this ( but I cannot explain the difference to i.vertex.z approach )

    Code (CSharp):
    1.  struct v2f
    2. {
    3.     float2 uv : TEXCOORD0;
    4.     float4 vertex : SV_POSITION;
    5.     float4 screenSpace : TEXCOORD1;
    6. };
    7.  
    8. v2f vert (appdata v)
    9. {
    10.     v2f o;
    11.     o.vertex = UnityObjectToClipPos(v.vertex);
    12.     o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    13.     o.screenSpace = ComputeScreenPos(o.vertex);
    14.     return o;
    15. }
    16.  
    17. fixed4 frag (v2f i) : SV_Target
    18. {
    19.     float depth = i.screenSpace.w;
    20.  
    21. }
    by the way: isn't Linear01Depth() function only for depth texture values? can I use normal z values?
     
    Last edited: May 24, 2023
  5. frankdervoelker

    frankdervoelker

    Joined:
    Nov 16, 2020
    Posts:
    11
    another thing: If I use the "i.vertex.z" value do calculate things I have different outputs in editor and play mode in unity... for example: I set objects to become black if z-value > 500. In the editor they become black when I move away just a little, when I press Play and start the game they become black much later. What could this be?
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    The
    SV_POSITION
    's .z in the fragment shader is the Z depth. The same depth value that's stored in the depth texture. So the depth related functions you'd use on the depth texture work on that value just as well.

    For perspective projections, the depth is non-linear, meaning 0.5 isn't halfway between the near and clip planes. The Linear01Depth() function transforms into a linear one so that 0.0 is the near plane, 1.0 is the far plane, and 0.5 is halfway between those two.

    The scene view uses a dynamic near and far plane depending on what you're looking at. When you press F to focus on an object, it'll adjust those values to ensure the selection is fully visible. Or you can override the near and far plane in the scene view's camera settings, accessible via the camera icon in the top right of that window. The game view uses a fixed near and far plane, which is whatever is set on the active camera game object being used to render from.

    For perspective projections, the
    ComputeScreenPos()
    output .w is the linear view space depth. It also happens to be the clip space's .w too, so it's the value you'd get from
    o.vertex.w
    in the vertex shader, and also still
    i.vertex.w
    in the fragment shader (the xyz values do not match between the vertex and fragment though).