How to access a specific cameras depth texture using _cameraRenderTexture in URP

I have searched for hours and I’m finding nothing useful. The documentation is lackluster as usual.
I am using URP, I have enabled DepthTexture in my URP asset and from what I gather every camera should create a depth texture now, my problem is I have zero idea where these textures are going or how to access them.

The official documentation says that ‘Depth textures are available for sampling in shaders as global shader properties. By declaring a sampler called _CameraDepthTexture you will be able to sample the main depth texture for the camera.’

So as far as I know the depth textures are accessed by using _cameraRenderTexture, so would I just put a Texture2D in the shadergraph and give it the reference ‘_cameraRenderTexture’ and feed it in to a SampleTexture2D? If that is the case then how do I specify which cameras depth texture to use if it is a global property? I need to use a specific cameras depth texture but if they are all writing to the same global property how on earth am I suppose to do that?

Everything about the documentation is confusing and ambiguous and it’s stressing me out.
Any help would be massively appreciated.

EDIT: For anybody in the same predicament I found this which should help:

Hi, you can either use the Scene Depth node or create a custom function node to sample the “_CameraDepthTexture” in URP shader graph.

The “_CameraDepthTexture” is a global texture property defined by URP. You can open the Frame Debugger to visualize the rendering process.

The second way is not straightforward, because you need to:

  • Add a custom function node
  • Add the shader code of sampling URP depth texture to a *.hlsl file
  • Assign the *.hlsl file to your custom function node

I believe it’s impossible (by default) to access the depth texture of CameraA during CameraB rendering. It may be cleared (share the same render texture) or not rendered yet.

However, you can try copying the depth texture you need to a temporary render texture once it’s rendered. You may need to manage the updates of copied depth texture yourself.

Thanks for pointing me in the right direction, I decided to try and store a copy of _CameraDepthTexture post render of the cameras I want to get the depth textures for and it worked.

I’ll share my findings for anybody interested.

After a lot of trial and error I found a way to get the depth textures of specified cameras, it’s a bit awkward but saved me from having to write a bunch of render passes (which I can’t for the life of me figure out because of the poor documentation atm) and I’m happy with the method I found and I think I prefer this method anyway but I’ll admit I am concerned it might not be as optimal as getting the depth texture from a render pass and I’ll explain why soon. Regardless it will do for now until we have some proper documentation on Render Passes and Scriptable Renderer Features which I can actually learn and understand.

So my plan was to get a specific cameras depth texture from _CameraDepthTexture, the problem was that it’s a global shader property so it will always return the depth texture of the last camera that was rendered. So then I thought about trying to copy the texture from that property post render of the cameras I want to get the depth textures for. So I had to find a way to do that now that OnPostRender doesn’t get called in URP. So I created a CameraManager script to call the URP equivalent of OnPreRender and OnPostRender by delegating methods to the RenderPipelineManager.

Here’s the CameraManager script. Put it on one object in your scene, like a GameController object or something.

using UnityEngine;
using UnityEngine.Rendering;

public class CameraManager : MonoBehaviour
{
    void OnEnable()
    {
        RenderPipelineManager.beginCameraRendering += PreRender;
        RenderPipelineManager.endCameraRendering += PostRender;
    }

    private void PreRender(ScriptableRenderContext _context, Camera _camera)
    {
        if (_camera.TryGetComponent<CameraRenderControl>(out CameraRenderControl _cameraRenderControl))
        {
            _cameraRenderControl.PreRender(_context, _camera);
        }
    }

    private void PostRender(ScriptableRenderContext _context, Camera _camera)
    {
        if (_camera.TryGetComponent<CameraRenderControl>(out CameraRenderControl _cameraRenderControl))
        {
            _cameraRenderControl.PostRender(_context, _camera);
        }
    }

    private void OnDisable()
    {
        RenderPipelineManager.beginCameraRendering -= PreRender;
        RenderPipelineManager.endCameraRendering -= PostRender;
    }
}

I then created a script called CameraRenderControl (Put this on all the cameras you want to get depth textures for) that would handle the PreRender and PostRender calls. This is where the magic happens. It’s worth noting that a cameras depth texture doesn’t seem to be created if it isn’t currently being rendered to a display or to a render texture and the only way I could find around that is to render the cameras I want to get the depth textures from to a render texture (If there’s a better way I’d like to know because I imagine this will have an effect on performance if you are rendering a ton of cameras to their own render textures, it’s ok for my particular use case because I only need the depth textures of 2 cameras at most, but I’m sure this will not be the case for other users and maybe I will even need more in the future)

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

public class CameraRenderControl : MonoBehaviour
{
    public Texture depthTexture;

    public List<GameObject> thingsToHide = new List<GameObject>();
    private List<GameObject> hiddenThings = new List<GameObject>();

    [Obsolete]
    public void PreRender(ScriptableRenderContext _context, Camera _camera)
    {
        // Do stuff here before the render, i.e. you could hide things specifically from this camera
        foreach (GameObject _thingToHide in thingsToHide)
        {
            _thingToHide.SetActive(false);
            hiddenThings.Add(_thingToHide);
        }

        // Manual Render (This might actually not be necessary but good to know how to do)
        UniversalRenderPipeline.RenderSingleCamera(_context, _camera); // NOTE: This is the obsolete method
                                                                      // the one below is the new broken one, use this until Unity fixes it

        //UniversalRenderPipeline.SubmitRenderRequest<UniversalAdditionalCameraData>(_camera, _camera.GetUniversalAdditionalCameraData());
    }

    public void PostRender(ScriptableRenderContext _context, Camera _camera)
    {
        // Get Camera depth texture (Must be rendering to a used display OR a render texture)
        Texture _camDepthTexture = Shader.GetGlobalTexture("_CameraDepthTexture");
       if (!depthTexture) depthTexture = new Texture2D(_camDepthTexture.width, _camDepthTexture.height, TextureFormat.RFloat, false);
        Graphics.CopyTexture(_camDepthTexture, depthTexture);

        // Reactivate the hidden things after the render
        foreach (GameObject _hiddenThing in hiddenThings)
        {
            _hiddenThing.SetActive(true);
        }
        hiddenThings.Clear();
    }
}

Now this script has a public reference to a usable depth texture which we can use for our purposes.

Hello!
I’ve been trying to make a custom node to use the _CameraDepthTexture but it seems impossible for me eto do!
I either get that the CameraDepthTexture is not defined… or it’s already defined!
Would you have a simple direction on how to retrieve and sample the CameraDepthTexture in a .hlsl custo node?
Thanks!

Use the scripts from the solution I posted. Read it to understand what they do and where they’re suppose to go and then use Shader.SetTexture or Material.SetTexture In the Camera RenderControl script after the depthTexture is created in the PostRender method.

Thanks for the reply.

I’ll check the scripts more in depth. I did honeestly just skinned through them and I thought that the issue was mostly related to multiple cameras.

I’m surprised anyway that accessing in the same shadergraph the SceneDepth node does not push for the creation of the _CameraDepthTexture.

Anyway, thanks again!