Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Question How to pass depth texture to shaders in custom SRP.

Discussion in 'General Graphics' started by Sluggy, Nov 20, 2021.

  1. Sluggy


    Nov 27, 2012
    In the default render pipelines provided by Unity there is a shader global named _CameraDepthTexture that is provided by default. I'm trying to mimic this feature in my own custom pipeline but I'm not familiar enough with the innerworkings of Unity's rendering system to know what exact steps need to be taken.

    I've ensured that the camera being passed to the pipeline's render method has it's depthTextureMode set to Depth. I'm not entirely sure what exactly this even does but I'm assuming it tells unity to create a rendertexture that will be used to contain the contents of the depth buffer at some point. I'm also assuming that it tells Unity that at some point it actually should copy that info from the depth buffer to the texture. However, I'm not entirely sure where or even if that is happening at all. A little clarification on this would help a lot.

    I know that somehow I have to get the contents of the depth buffer passed to the shader using something like
    Code (CSharp):
    1. cmdDepthOpaque.SetGlobalTexture("_CameraDepthTexture", theDepthTextureINeed);
    But I have no idea how I'm actually supposed to get that depth texture. The camera does not appear to have any by default when I enable it's depthTextureMode. I've also tried creating a render texture on the fly, doing a depth presspass, and then passing *that* rendertexture the shader globals but it seems to just be giving me some very weird and glitchy results.

    Does anyone have any experience with depth buffers and depth textures in their own custom renderpipelines or does anyone have enough general knowledge of Unity's internals that they could at least explain some basics so that I can know what direction I need to take to get access to the depth info in shaders using my own pipeline?
  2. Sluggy


    Nov 27, 2012
    I fiddled around with things for a bit and eventually discovered the BuiltinRenderTextureType enum. It seems this contains a list of identifiers for common things in Unity's rendering system. However, it appears that the Depth, DepthNormals, and ResolvedDepth all were invalid and would throw errors in the editor if I tried to access. I'm not sure what the exact lifetime of these temporary textures is or if I just need to do something else to get them to work. I tried accessing them at various different points in my pipeline but with no luck.. however...

    I did still manage to come up with a solution. Now that I could get access to the default render target via BuiltinRenderTextureType.CameraTarget, I was able to create my own temporary buffer, render a depth pre-pass to that, bind that texture to the shader global _CameraDepthTexture, and then finally revert back to the original render target and continue rendering as normal. The following function is called just before normal rendering in my pipeline.

    Code (CSharp):
    1. void DepthPass(SLWTRenderPipeline pipeline, ref ScriptableRenderContext context, ref Camera camera, ref CullingResults cullResults, ref ShaderTagId[] shaderTags, LayerMasks renderingLayerMask = LayerMasks.AllButDecals)
    2.         {
    3.             CommandBuffer depthCmd = new CommandBuffer
    4.             {
    5.                 name = "Depth Pre-Pass"
    6.             };
    8.             //cache current render target so that we can reset it after the depth pass,
    9.             //then replace it with a new rendertarget so that we can write to the depth buffer
    10.             var currRT = BuiltinRenderTextureType.CameraTarget;
    11.             depthCmd.GetTemporaryRT(DepthPrepassTextureId, camera.pixelWidth, camera.pixelHeight, 24, FilterMode.Point, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default, 1, false);
    12.             var depthTexture = DepthPrepassTextureId;
    14.             depthCmd.SetRenderTarget(depthTexture);
    15.             depthCmd.ClearRenderTarget(true, true,;
    16.             context.ExecuteCommandBuffer(depthCmd);
    17.             depthCmd.Clear();
    19.             //compile a list of all solid geometry to be rendered
    20.             var sortSettings = new SortingSettings(Camera) { criteria = SortingCriteria.CommonTransparent };
    21.             var filterSettings = new FilteringSettings(RenderQueueRange.opaque, -1, (uint)renderingLayerMask);
    22.             var drawSettings = new DrawingSettings(shaderTags[0], sortSettings);
    23.             for (int i = 1; i < shaderTags.Length; i++)
    24.                 drawSettings.SetShaderPassName(i, shaderTags[i]);
    26.             //replace all objects' shaders with a simple depth-write-only shader
    27.             drawSettings.overrideMaterial = pipeline.DepthWriteMaterial;
    29.             ConfigureDrawReduction(ref drawSettings);
    30.             context.DrawRenderers(cullResults, ref drawSettings, ref filterSettings);
    31.             depthCmd.SetGlobalTexture(this.DepthTextureShaderId, depthTexture, RenderTextureSubElement.Depth);
    32.             context.ExecuteCommandBuffer(depthCmd);
    33.             depthCmd.Clear();
    35.             //reset render target
    36.             depthCmd.SetRenderTarget(currRT);
    37.             context.ExecuteCommandBuffer(depthCmd);
    38.             depthCmd.Clear();
    39.             depthCmd.Release();
    41.         }
    This still feels like a waste and I'd much rather just do my normal rendering and then somehow grab the depth texture that resulted from it and bind that so that additional passes (such as decals) have access to it. If anyone has any ideas on how that could be accomplished I'd be grateful to hear them. In the meantime, hopefully this post will help others in the future with similar problems.
    forteller likes this.