Depth Texture on Objects/Materials

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?

Shader "Custom/DepthShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 pos : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                half2 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
            };

            sampler2D _MainTex;
            uniform sampler2D_float _CameraDepthTexture;
            float _Intensity;
            float4 _OverlayColor;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos (v.pos);
                o.uv = MultiplyUV(UNITY_MATRIX_TEXTURE0, v.uv);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float depth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, i.uv));
                depth = pow(Linear01Depth(depth), .85);


                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                col.rgb *= depth;
               
                return col;
            }
            ENDCG
        }
    }
}

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.

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);

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 )

 struct v2f
{
    float2 uv : TEXCOORD0;
    float4 vertex : SV_POSITION;
    float4 screenSpace : TEXCOORD1;
};

v2f vert (appdata v)
{
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    o.screenSpace = ComputeScreenPos(o.vertex);
    return o;
}

fixed4 frag (v2f i) : SV_Target
{
    float depth = i.screenSpace.w;

}

by the way: isn’t Linear01Depth() function only for depth texture values? can I use normal z values?

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?

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).