Search Unity

Writing into a render texture using depth buffer from another render texture, how to do it?

Discussion in 'General Graphics' started by iSinner, Apr 6, 2015.

  1. iSinner

    iSinner

    Joined:
    Dec 5, 2013
    Posts:
    201
    I have 2 cameras, first one is the main camera and it draws all the geometry as usual, and the second one is a light camera that draws some 2d lights. And then i have a post effect that Blits those two textures.

    So the problem is, i need to render some transparent geometry (some 2d light) into a render texture, lets call it 'LightRT'. But i need to occlude it with the depth buffer values from what was rendered by main camera, which renders into RenderTexture.active.

    I'm trying to do it like this, in the image effect:
    Code (CSharp):
    1. protected void OnRenderImage(RenderTexture source, RenderTexture destination)
    2.     {
    3.      
    4.         Graphics.SetRenderTarget(LightRT.colorBuffer, source.depthBuffer);
    5.  
    6.         ImageEffectCamera.Render();
    7.  
    8.         Graphics.SetRenderTarget(source.colorBuffer, source.depthBuffer);
    9.         Material.SetTexture("_Overlay", LightRT);
    10.         Graphics.Blit(source, destination, Material);
    11.  
    12.      
    13.     }
    and in the shader of the light i set ZTest to LEqual, which should occlude the light, right?

    Light shader:
    Code (CSharp):
    1. Shader "01DEVS/Light 2D/Screen"
    2. {
    3.     Properties
    4.     {
    5.         _Color("Color (RGBA)",Color) = (1,1,1,1)
    6.         _MainTex ("Lightmap (RGBA)", 2D) = "white" {}
    7.         [Enum(UnityEngine.Rendering.CompareFunction)]_StencilComp("Stencil Comparison", Float) = 8
    8.         _Stencil ("Stencil ID", Float) = 0
    9.         [Enum(UnityEngine.Rendering.StencilOp)]_StencilOp ("Stencil Operation", Float) = 0
    10.     }
    11.  
    12.     SubShader
    13.     {
    14.         Tags
    15.         {
    16.             "Queue"="Transparent"
    17.             "RenderType"="Light"
    18.         }
    19.         Pass
    20.         {
    21.             Stencil
    22.             {
    23.                 Ref [_Stencil]
    24.                 Comp [_StencilComp]
    25.                 Pass [_StencilOp]
    26.             }
    27.             Name "BASE"
    28.             Cull Back
    29.             Lighting Off
    30.             ZWrite Off
    31.             ZTest LEqual
    32.             ColorMask RGBA
    33.             Blend OneMinusDstColor One
    34.             CGPROGRAM
    35.  
    36.             #pragma vertex vert
    37.             #pragma fragment frag
    38.        
    39.             #include "UnityCG.cginc"
    40.        
    41.          
    42.             sampler2D _MainTex;
    43.             half4 _MainTex_ST;
    44.             fixed4 _Color;
    45.             struct appdata_mine {
    46.                 float4 vertex : POSITION;
    47.                 float4 texcoord : TEXCOORD0;
    48.                 fixed4 color : COLOR;
    49.             };
    50.        
    51.             struct v2f {
    52.                 float4 vertex : POSITION;
    53.                 float2 uv : TEXCOORD0;
    54.                 fixed4 color : COLOR;
    55.              
    56.             };
    57.        
    58.             v2f vert( appdata_mine v ){
    59.                 v2f o;
    60.                 o.vertex = mul( UNITY_MATRIX_MVP, v.vertex );
    61.                 o.uv = TRANSFORM_TEX( v.texcoord, _MainTex );
    62.                 o.color = v.color * _Color;
    63.              
    64.                 return o;
    65.             }
    66.        
    67.             half4 frag( v2f i ) : COLOR
    68.             {
    69.                 return i.color;
    70.             }
    71.        
    72.             ENDCG
    73.         }
    74.     }
    75. }
    The light is not occluded, and i have no idea why, can anyone explain why?
     
    Last edited: Apr 6, 2015
  2. iSinner

    iSinner

    Joined:
    Dec 5, 2013
    Posts:
    201
    I also tried to enable depth rendering in main camera, like this:
    Code (CSharp):
    1. CachedCamera.depthTextureMode = DepthTextureMode.Depth;
    and assign the LightRT render texture into which the light is rendered to the camera which renders the light,
    and then in the light shader to compare the computed light's depth value to the one present in the _CameraDepthTexture, like this:
    Code (CSharp):
    1. Shader "01DEVS/Light 2D/Screen"
    2. {
    3.     Properties
    4.     {
    5.         _Color("Color (RGBA)",Color) = (1,1,1,1)
    6.         _MainTex ("Lightmap (RGBA)", 2D) = "white" {}
    7.         [Enum(UnityEngine.Rendering.CompareFunction)]_StencilComp("Stencil Comparison", Float) = 8
    8.         _Stencil ("Stencil ID", Float) = 0
    9.         [Enum(UnityEngine.Rendering.StencilOp)]_StencilOp ("Stencil Operation", Float) = 0
    10.     }
    11.  
    12.     SubShader
    13.     {
    14.         Tags
    15.         {
    16.             "Queue"="Transparent"
    17.             "RenderType"="Light"
    18.         }
    19.         Pass
    20.         {
    21.             Stencil
    22.             {
    23.                 Ref [_Stencil]
    24.                 Comp [_StencilComp]
    25.                 Pass [_StencilOp]
    26.             }
    27.             Name "BASE"
    28.             Cull Back
    29.             Lighting Off
    30.             ZWrite Off
    31.             ZTest Always
    32.             ColorMask RGBA
    33.             Blend OneMinusDstColor One
    34.             CGPROGRAM
    35.  
    36.             #pragma vertex vert
    37.             #pragma fragment frag
    38.      
    39.             #include "UnityCG.cginc"
    40.      
    41.        
    42.             sampler2D _CameraDepthTexture;
    43.  
    44.             sampler2D _MainTex;
    45.             half4 _MainTex_ST;
    46.             fixed4 _Color;
    47.             struct appdata_mine {
    48.                 float4 vertex : POSITION;
    49.                 float4 texcoord : TEXCOORD0;
    50.                 fixed4 color : COLOR;
    51.             };
    52.      
    53.             struct v2f {
    54.                 float4 vertex : POSITION;
    55.                 float2 uv : TEXCOORD0;
    56.                 fixed4 color : COLOR;
    57.                 float4 projPos : TEXCOORD1;
    58.             };
    59.      
    60.             v2f vert( appdata_mine v ){
    61.                 v2f o;
    62.                 o.vertex = mul( UNITY_MATRIX_MVP, v.vertex );
    63.                 o.uv = TRANSFORM_TEX( v.texcoord, _MainTex );
    64.                 o.color = v.color * _Color;
    65.                 o.projPos = ComputeScreenPos(o.vertex);
    66.                 return o;
    67.             }
    68.      
    69.             half4 frag( v2f i ) : COLOR
    70.             {
    71.                 //Get the distance to the camera from the depth buffer for this point
    72.                 float sceneZ = LinearEyeDepth (tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos)).r);
    73.                 float partZ = i.projPos.z;
    74.                 if(partZ > sceneZ) return half4(1,0,0,1);
    75.                 return half4(0,1,0,1);
    76.             }
    77.      
    78.             ENDCG
    79.         }
    80.     }
    81. }
    so i output green if the fragment is in front of the geometry, and red if it is behind. All i get is green, i.e. like there is no depth information in the _CameraDepthTexture.

    The code in the image effect is as follows:
    Code (CSharp):
    1. protected void OnRenderImage(RenderTexture source, RenderTexture destination)
    2.     {  
    3.         ImageEffectCamera.Render();
    4.         Material.SetTexture("_Overlay", LightRT);
    5.         Graphics.Blit(source, destination, Material);
    6.    
    7.     }
    I don't get what is the problem, can anyone help?
     
    Last edited: Apr 6, 2015
  3. iSinner

    iSinner

    Joined:
    Dec 5, 2013
    Posts:
    201
    So i set up very simple scene, i have a cube and a quad that intersects it, the quad is set to separate layer that is rendered only by the light camera, and has a light shader on it.

    notice that in the scene view, scene view camera is rendering all layers, the Light layer and the cube layer, so i get the correct results, where the light quad is culled by the cube, it gets red. But in the game view, the depth information is missing, so i get green everywhere. The image effect just multiplies the light texture with the texture generated by the main camera.
     
  4. iSinner

    iSinner

    Joined:
    Dec 5, 2013
    Posts:
    201
    This is what the frame debugger is showing:
    Depth rendering: (notice the render texture name, Camera DepthTexture)

    Main camera rendering (why is the depth buffer cleared?) (notice the render texture name, ImageEffects Temp)

    Image effect(light) camera rendering: (notice the render texture name, LightmapData Render Texture 2)

    And the blitting:


    So it seems that the depth information written by the camera (Camera.depthTextureMode = DepthTextureMode.Depth) is written to a render texture called "Camera DepthTexture"
    Then main camera renders the cube into "ImageEffects Temp"
    and then the image effect is rendered into "LightmapData Render Texture 2" which is created by me.
    When i acces _CameraDepthTexture in the light shader, which depth texture is it? because it does not seem to be the "Camera DepthTexture", because the result in the game view is all green, when it should be red where the cube is.

    I have tried to use the colorbuffer from "LightmapData Render Texture 2" and the depth buffer from the RenderTexture.active ( i wrote about this i nthe first post), but i can't get it to work.

    Any ideas?
     
  5. raja-bala

    raja-bala

    Joined:
    Jul 11, 2012
    Posts:
    29
    Does your light camera's render target have both color and depth buffers? If so, can you make it color buffer only (by setting depth to 0 in the RenderTexture constructor)?

    Also, what's the clear settings for the light camera? You could say "don't clear" and do a manual clear of the color buffer prior to rendering via GL.Clear

    I had to do something similar recently (use the main scene's depth buffer with another color buffer), but I didn't have a secondary camera. I submitted the geometry I needed via DrawMeshNow (instead of using quads on a separate layer).
     
    iSinner likes this.
  6. iSinner

    iSinner

    Joined:
    Dec 5, 2013
    Posts:
    201
    Yes, it has a depth buffer, but i can't remove it because i need the stencil, which as far as i know is bound with depth buffer.
    That is exactly what saved my case(and something more, later on it), automatic clearing was messing things up, it was clearing the wrong texture.

    So i managed to solve the problem with your advice plus something extra, that extra is
    Code (CSharp):
    1. ImageEffectCamera.SetTargetBuffers(RenderTexture.colorBuffer, source.depthBuffer);
    this allows me to set the color buffer from the light camera(ImageEffectCamera) render target, and depth buffer from the screen. I also do not need the main camera to render the depth into separate depth texture, which is very nice.

    This is the result:
    Image effect camera clear flags set to nothing.
    My image effect code:
    Code (CSharp):
    1. protected void OnRenderImage(RenderTexture source, RenderTexture destination)
    2.     {
    3.         //set our lightmap texture as active render texture
    4.         var active = RenderTexture.active;
    5.         RenderTexture.active = RenderTexture;
    6.         //clear the lightmap
    7.         GL.Clear(true, true, Color.clear);
    8.         RenderTexture.active = active;
    9.         //RenderTexture is the target texture of the ImageEffectCamera
    10.         ImageEffectCamera.SetTargetBuffers(RenderTexture.colorBuffer, source.depthBuffer);
    11.         ImageEffectCamera.Render();
    12.  
    13.         Material.SetTexture("_Overlay", RenderTexture);
    14.         Graphics.Blit(source, destination, Material, (int)_blendMode);  
    15.     }
    Light shader:
    Code (CSharp):
    1. Shader "01DEVS/Light 2D/Screen"
    2. {
    3.     Properties
    4.     {
    5.         _Color("Color (RGBA)",Color) = (1,1,1,1)
    6.         _MainTex ("Lightmap (RGBA)", 2D) = "white" {}
    7.         [Enum(UnityEngine.Rendering.CompareFunction)]_StencilComp("Stencil Comparison", Float) = 8
    8.         _Stencil ("Stencil ID", Float) = 0
    9.         [Enum(UnityEngine.Rendering.StencilOp)]_StencilOp ("Stencil Operation", Float) = 0
    10.     }
    11.  
    12.     SubShader
    13.     {
    14.         Tags
    15.         {
    16.             "Queue"="Transparent"
    17.             "RenderType"="Light"
    18.         }
    19.         Pass
    20.         {
    21.             Stencil
    22.             {
    23.                 Ref [_Stencil]
    24.                 Comp [_StencilComp]
    25.                 Pass [_StencilOp]
    26.             }
    27.             Name "BASE"
    28.             Cull Back
    29.             Lighting Off
    30.             ZWrite Off
    31.             ZTest LEqual
    32.             ColorMask RGBA
    33.             Blend OneMinusDstColor One
    34.             CGPROGRAM
    35.  
    36.             #pragma vertex vert
    37.             #pragma fragment frag
    38.          
    39.             #include "UnityCG.cginc"
    40.          
    41.            
    42.             sampler2D _CameraDepthTexture;
    43.  
    44.             sampler2D _MainTex;
    45.             half4 _MainTex_ST;
    46.             fixed4 _Color;
    47.             struct appdata_mine {
    48.                 float4 vertex : POSITION;
    49.                 float4 texcoord : TEXCOORD0;
    50.                 fixed4 color : COLOR;
    51.             };
    52.          
    53.             struct v2f {
    54.                 float4 vertex : POSITION;
    55.                 float2 uv : TEXCOORD0;
    56.                 fixed4 color : COLOR;
    57.             };
    58.          
    59.             v2f vert( appdata_mine v ){
    60.                 v2f o;
    61.                 o.vertex = mul( UNITY_MATRIX_MVP, v.vertex );
    62.                 o.uv = TRANSFORM_TEX( v.texcoord, _MainTex );
    63.                 o.color = v.color * _Color;
    64.                 return o;
    65.             }
    66.          
    67.             half4 frag( v2f i ) : COLOR
    68.             {
    69.                 half4 overlay = tex2D( _MainTex, i.uv ) * i.color;
    70.                 return overlay;
    71.             }
    72.          
    73.             ENDCG
    74.         }
    75.     }
    76. }
    I dont need to do manual ZTesting, because the dept hbuffer the light is tested against is from the main camera, ZTest LEqual does everything for me, which is also very nice.

    And here are the frame debugger results:
    ImageEffects Temp happens to be the screen buffer (to which the main camera is rendering), this is also the source RenderTexture which comes into the OnRenderImage method.


    Notice that the renderTarget of the light's camera is being cleared (the manual clearing we did in the OnRenderImage method)


    You can see that the depth buffer of the light's camera renderTarget is the one from the main camera, because we set it before rendering the light quad.
    This bit of code:
    Code (CSharp):
    1. ImageEffectCamera.SetTargetBuffers(RenderTexture.colorBuffer, source.depthBuffer);
    Notice that frame debugger is set to show the depth texture


    And the final result after blitting:


    Thanks for the help!
     
    IgorAherne likes this.
  7. BearHugMark

    BearHugMark

    Joined:
    Feb 21, 2016
    Posts:
    21
    Thank you so much for sharing! Took me AAAGGESS to get this to work, but there was a subtle difference in my frame debugger (big thanks for sharing yours!).

    Screen Shot 2017-03-19 at 13.56.09.png

    I had "Camera.AAResolve" appearing in my stack which caused the ZBuffer to get corrupted by the time I could render my cube.

    Screen Shot 2017-03-19 at 13.53.25.png

    I disabled Anti-Aliasing in my quality settings and BINGO! It worked a charm :)

    Screen Shot 2017-03-19 at 14.00.21.png

    Thanks for sharing and if anyone has any corruption in their Depth buffer, try disabling Anti-Aliasing!
     
    infernalage likes this.
  8. infernalage

    infernalage

    Joined:
    Jan 9, 2015
    Posts:
    3
    I have to thank you both for the advices, i managed to reuse the main camera depth buffer with SetTargetBuffers + Antialiasing off, that fix the rendering of color buffer; However, depth testing wasn't working because the camera was clearing the z+color+stencil before rendering so i had to turn clearflags off and do it manually (as iSinner did).

    Anyway, any idea on how to enable antialiasing + shared depth buffer ?
     
  9. BearHugMark

    BearHugMark

    Joined:
    Feb 21, 2016
    Posts:
    21
    We ended up keeping anti-aliasing turned off, and haven't yet found a work around for it sadly. Glad someone else got some benefit from this thread! :)
     
    infernalage likes this.
  10. infernalage

    infernalage

    Joined:
    Jan 9, 2015
    Posts:
    3
    I guess i ll look for FXAA on mobile instead of MSAA
     
  11. qiu_lirui

    qiu_lirui

    Joined:
    Oct 28, 2017
    Posts:
    7
    I've tried to use customRenderTexture + Display.main.depthBuffer
    in CommandBuffer.SetRenderTarget( ). Ends up with this error: You're trying to mix color and depth buffers from RenderTexture and from screen.

    The solution is:Write my code in OnRenderImage(RenderTexture source, RenderTexture destination)
    and use customRenderTexture + source.depthBuffer. It works fine ! Showing that source.depthBuffer is not a real screenDepthBuffer.