Search Unity

Sampling depth buffer from a RenderTexture

Discussion in 'Shaders' started by Daerst, Oct 21, 2016.

  1. Daerst

    Daerst

    Joined:
    Jun 16, 2016
    Posts:
    275
    Hi,

    I have a camera that renders to a RenderTexture with depth buffer. I then use this camera's RenderTexture as a resource in a shader on a different camera.

    I know I can query the rendering camera's depth buffer using sampler2D _CameraDepthTexture (which is automatically set somewhere in the Unity internals). Is there any way to sample the depth texture of the previously created RenderTexture though?

    Thanks in advance!
     
    DANV_C likes this.
  2. David-Lycan

    David-Lycan

    Joined:
    Nov 25, 2012
    Posts:
    16
    I'm not totally sure but you may want to use Camera.SetTargetBuffers:
    https://docs.unity3d.com/ScriptReference/Camera.SetTargetBuffers.html

    With that you can provide the depthbuffer from a previous RenderTexture to your second camera.

    But if you need to sample the depth from that previous render then I think the shader used by that previous render needs to output depth as color before being assigned to your post effect shader. As far as I'm aware there's no other way to convert a depthbuffer into a RenderTexture to be sampled.

    I found this other post which may help:
    http://answers.unity3d.com/questions/760126/copying-depth-from-one-rendertexture-to-another.html

    Hope that helps :)
     
  3. Daerst

    Daerst

    Joined:
    Jun 16, 2016
    Posts:
    275
    @David-Lycan, thanks a lot for your reply.

    To provide some detail: I am trying to implement a post-FX-based Fog Of War system. I have a camera that renders the scene without hiders (i.e. everything that should not be visible behind Fog Of War) into a render texture, and one that renders the whole scene (with hiders) to the screen. Then a post-effect reconstructs the world position from the depth buffer and overlay the hider-less image from the render texture where the world position is fogged. This works for top down, but once I look at an angle and a hider is invisible, I need the depth value behind, that is from the render texture. So, in total I need both color and depth buffers.

    From the links you posted I take it that I'd need to render the scene without hiders to a texture, then again with replacement shader for depth values to another texture, then once again to the screen where I can sample both color and depth at once and use the other render textures as required. A third pass is of course not ideal, but might do as a workaround. Still, I would prefer a way to directly sample a render texture's depth buffer, if technically possible :)

    Do you see any way in which _LastCameraDepthTexture could help me?
     
    Last edited: Oct 22, 2016
  4. Daerst

    Daerst

    Joined:
    Jun 16, 2016
    Posts:
    275
    Here is a solution that I found for my case:

    1) Render the scene using your main camera (A).
    2) In OnRenderImage of camera A (where you will apply your post FX), call Render() on the second camera (B) which is set to render to a render texture. Be sure to disable the camera component so it doesn't render automatically.
    3) In your image effect, use the render texure as usual. _CameraDepthTexture will contain A's depth texture, while _LastCameraDepthTexture will contain the depth texture of the last camera that has rendered - which is camera B.

    For more than 2 RenderTextures you still need to use the replacement shader workaround.
     
    Mingyang97 likes this.
  5. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    Actually, the solution of David-Lycan also works fine. Make one RenderTexture without depth buffer and one with depth buffer and set it to depth format. Then use SetTargetBuffers to apply them as targets for the camera. You can use the depth as a texture source anywhere.

    Code (csharp):
    1.  
    2. target = new RenderTexture (width, height, 0, RenderTextureFormat.Default);
    3. targetDepth = new RenderTexture (width, height, 24, RenderTextureFormat.Depth);
    4. camera.SetTargetBuffers (target.colorBuffer, targetDepth.depthBuffer);
    5.  
     
  6. Daerst

    Daerst

    Joined:
    Jun 16, 2016
    Posts:
    275
    @jvo3dc, I was not aware that you could use @David-Lycan's suggestion (SetTargetBuffers) this way. This is a very good universal solution, thanks!
     
  7. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    Using a color rendertexture and a depth rendertexture by mixing them with SetTargetBuffers doesn't work as of Unity 5.6b and DX11
    The rendered geometry will not use the depth texture and will behave as if no z-buffer was present. Stencil does the same.
    Odly enough, if you manually mask the color output in a shader using ColorMask 0 ,thus forcing the shader to only render to the depth buffer, it WILL work and write to the depth rendertexture, but only in this case.
    Reading the z-buffer directly doesn't seem to be possible in unity.
    If anyone knows anything about the subject, I would be glad to be proven wrong!
     
  8. cpetry

    cpetry

    Joined:
    Jun 30, 2014
    Posts:
    29
    Is there some solution to this problem?

    I would also like to use a shader-written depth buffer as a RenderTexture.
    The solution of @David-Lycan does not work for me (Unity 5.5.2f1).
     
  9. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869
    You can modify the "builtin_shaders\DefaultResources\Extra\Internal-DepthNormalsTexture.shader" for this purpose.
    This is the shader used internally by unity to render the depth and normals textures.
    You can find it in the "builtin_shaders" file in the extra download ressources of the unity download page.
    Then you will need put the modified shader in your assets folder in your project and configure the Graphics Settings of your project to use this custom made shader by selecting it in the "m_DepthNormals" field. (be sure to enable the DEBUG MODE of the inspector window in unity by clicking in the little icon nect to the lock, up right)
     
  10. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    Maybe you should report a bug on this. It's already quite a task to sample the depth buffer from another RenderTexture. If this doesn't work anymore, there a no options left besides rendering twice I think.
     
    CGDever likes this.
  11. ViniciusGraciano

    ViniciusGraciano

    Joined:
    May 19, 2013
    Posts:
    13
    Bump. Can anyone shed some light in this? I am trying to get the depth buffer for a custom Ambient Occlusion effect and I do not want to render the scene twice.
     
  12. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,869