How to render the depth of transparent objects to _CameraDepthTexture

I want to write the depth information of the transparent object to _CameraDepthTexture,But I don’t know what to do.
I use DepthNormalsFeature to render depth:


The two balls in the middle are transparent and the others are opaque.

and c#:

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class DepthNormalsFeature : ScriptableRendererFeature {
    class RenderPass : ScriptableRenderPass {

        private Material material;
        private RenderTargetHandle destinationHandle;
        private List<ShaderTagId> shaderTags;
        private FilteringSettings filteringSettings;

        public RenderPass() : base() {
            this.material = CoreUtils.CreateEngineMaterial("My/Internal-DepthNormalsTexture"); ;
            this.shaderTags = new List<ShaderTagId>() {
                new ShaderTagId("DepthOnly"),
                // Render shader graph transparent materials
                new ShaderTagId("DepthNormalsOnly")
            };
            // RenderQueueRange.all: Render transparent materials
            this.filteringSettings = new FilteringSettings(RenderQueueRange.all);
            renderPassEvent = RenderPassEvent.AfterRenderingPrePasses;
            destinationHandle.Init("_DepthNormalsTexture");
        }

        public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor) {
            cmd.GetTemporaryRT(destinationHandle.id, cameraTextureDescriptor, FilterMode.Point);
            ConfigureTarget(destinationHandle.Identifier());
            ConfigureClear(ClearFlag.All, Color.black);
        }

        public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) {
            var drawSettings = CreateDrawingSettings(shaderTags, ref renderingData, renderingData.cameraData.defaultOpaqueSortFlags);

            drawSettings.overrideMaterial = material;
            context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filteringSettings);
        }

        public override void FrameCleanup(CommandBuffer cmd) {
            cmd.ReleaseTemporaryRT(destinationHandle.id);
        }
    }

    private RenderPass renderPass;

    public override void Create() {
        this.renderPass = new RenderPass();
    }

    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) {
        renderer.EnqueuePass(renderPass);
    }
}

shader:

Shader "My/Internal-DepthNormalsTexture"
{
    SubShader
    {
        Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }
       
        Pass
        {
            Name "Depth-Normal"
           
            HLSLPROGRAM
            HLSLcc by default
            #pragma prefer_hlslcc gles
            #pragma exclude_renderers d3d11_9x
            #pragma target 2.0
           
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
           
            #pragma vertex vert
            #pragma fragment frag
           
            struct Attributes
            {
                float4 positionOS: POSITION;
                float3 normalOS: NORMAL;
            };
           
            struct Varyings
            {
                float4 positionCS: SV_POSITION;
                float4 normal_depth: TEXCOORD0;
            };
           
            // Encoding/decoding view space normals into 2D 0..1 vector
            float2 EncodeViewNormalStereo(float3 n)
            {
                float kScale = 1.7777;
                float2 enc;
                enc = n.xy / (n.z + 1);
                enc /= kScale;
                enc = enc * 0.5 + 0.5;
                return enc;
            }
           
            // Encoding/decoding [0..1) floats into 8 bit/channel RG. Note that 1.0 will not be encoded properly.
            float2 EncodeFloatRG(float v)
            {
                float2 kEncodeMul = float2(1.0, 255.0);
                float kEncodeBit = 1.0 / 255.0;
                float2 enc = kEncodeMul * v;
                enc = frac(enc);
                enc.x -= enc.y * kEncodeBit;
                return enc;
            }
           
            float4 EncodeDepthNormal(float depth, float3 normal)
            {
                float4 enc;
                enc.xy = EncodeViewNormalStereo(normal);
                enc.zw = EncodeFloatRG(depth);
                //enc.zw = float2(0, 0);
                return enc;
            }
           
            Varyings vert(Attributes input)
            {
                Varyings output = (Varyings)0;
               
                VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
               
                output.positionCS = vertexInput.positionCS;
                output.normal_depth.xyz = mul((float3x3)UNITY_MATRIX_IT_MV, input.normalOS);
                output.normal_depth.w = - (vertexInput.positionVS.z * _ProjectionParams.w);
                return output;
            }
           
            half4 frag(Varyings input): SV_Target
            {
                return EncodeDepthNormal(input.normal_depth.w, input.normal_depth.xyz);
            }
            ENDHLSL
           
        }
    }
}

Then in the copy depth stage, the two transparent balls disappeared

I want to use the with transparent material depth information later in the rednerobjects phase _Cameradepthtexture, but I can’t get it

How can I write transparent object depth information to _Cameradepthtexture?

Instead of writing to it directly, do you just want to update _CameraDepthTexture again?

_CameraDepthTexture is automatically handled by Unity based on various factors (what RenderFeatures you’re using, if you have that toggle checked on, stuff like that). It’s just a blit of the current working depth to a new texture, so you can read the results from that moment onward despite depth still being written to in upcoming draws. I believe the blit is always done either after Opaque geometry is rendered or maybe after the Skybox is rendered (either way, before transparency queue).

If you want to ‘update’ _CameraDepthTexture’s results, you’ll need to do another blit. URP is written by people who don’t make games, it seems, and so they don’t provide any easy way to do this. Your best bet is to just have your own custom RenderFeature/RenderPass which does the same blit at whichever moment you need.

2 Likes

I want to render outlines for transparent objects, so I need to use SHADERGRAPH_SAMPLE_SCENE_DEPTH, but transparent shader do not render to by default _CameraDepthTexture

// Weights for the x component
static float sobelXMatrix[9] = {
    1, 0, -1,
    2, 0, -2,
    1, 0, -1
};

// Weights for the y component
static float sobelYMatrix[9] = {
    1, 2, 1,
    0, 0, 0,
    -1, -2, -1
};

void DepthSobel_float(float2 UV, float Thickness, out float Out) {
    float2 sobel = 0;
    [unroll] for (int i = 0; i < 9; i++) {
        float depth = SHADERGRAPH_SAMPLE_SCENE_DEPTH(UV + sobelSamplePoints[i] * Thickness);
        sobel += depth * float2(sobelXMatrix[i], sobelYMatrix[i]);
    }
    Out = length(sobel);
}

In versions < 22.1, the CopyDepth pass happens always after the Opaque pass, so the copied depth will miss any transparent depth. The solution to that would be to write your own CopyDepthPass render feature (you can look at CopyDepthPass.cs as an implementation example).

In 22.1 we added a new “Copy Depth Mode” option to the renderer that allows to copy the depth after the transparent pass instead of using the opaque one:

8037557--1036631--upload_2022-4-11_13-48-42.png

Hi there I have been trying to get this working but I have hit a wall.
I set up a test environment with two opaque cubes and a transparent one.
I placed them into a giant cube that has the test shader on it, basically it just highlights the object White if it detects its depth. As you can see in the picture only the Opaque cubes (the sides) show up. The middle ones just doesn’t interact at all. I tired Depth Write Always and a million other things i could think of but nothing. Any ideas? Thanks

8811583--1198804--DepthTest.png 8811583--1198807--DepthTestShader.png 8811583--1198810--RenderSettings.png