Search Unity

Question Render texture with depth for default fog issue

Discussion in 'Shaders' started by aNormalGuy, Apr 21, 2021.

  1. aNormalGuy

    aNormalGuy

    Joined:
    Jul 22, 2013
    Posts:
    36
    So in our game you can walk through portals between areas.

    I used Sebastian League Portals video as a start:




    The problem: The default fog from the Light Settings in Unity isn't being rendered through the portal, as you can see it pop when you walk through it. The reason it pops is because the main camera that's on the player is the one that sees the fog and not the portal camera.

    My goal: Have the camera that renders what the portal sees also make sure the fog is rendered on the actual plane/render texture.

    Here's the code for the portal shader, I'm no shader expert but it seems pretty straight forward with taking the color and applying it to the material.
    Code (CSharp):
    1. Shader "Custom/Portal"
    2. {
    3.     Properties
    4.     {
    5.         _InactiveColour ("Inactive Colour", Color) = (1, 1, 1, 1)
    6.         _Color("Color", Color) = (1, 0, 0, 0.4)
    7.     }
    8.     SubShader
    9.     {
    10.         Tags { "Queue"="Transparent" "RenderType"="Transparent" }
    11.         Blend SrcAlpha OneMinusSrcAlpha
    12.         Cull Off
    13.  
    14.         Pass
    15.         {
    16.             CGPROGRAM
    17.             #pragma vertex vert
    18.             #pragma fragment frag
    19.             #include "UnityCG.cginc"
    20.  
    21.             struct appdata
    22.             {
    23.                 float4 vertex : POSITION;
    24.             };
    25.  
    26.             struct v2f
    27.             {
    28.                 float4 vertex : SV_POSITION;
    29.                 float4 screenPos : TEXCOORD0;
    30.             };
    31.  
    32.             sampler2D _MainTex;
    33.             float4 _InactiveColour;
    34.             int displayMask = 0; // set to 1 to display texture, otherwise will draw test colour
    35.             float4 _Color;
    36.          
    37.  
    38.             v2f vert (appdata v)
    39.             {
    40.                 v2f o;
    41.                 o.vertex = UnityObjectToClipPos(v.vertex);
    42.                 o.screenPos = ComputeScreenPos(o.vertex);
    43.                 return o;
    44.             }
    45.  
    46.             fixed4 frag (v2f i) : SV_Target
    47.             {
    48.                 float2 uv = i.screenPos.xy / i.screenPos.w;
    49.                 fixed4 portalCol = tex2D(_MainTex, uv);
    50.                 portalCol = portalCol * _Color;
    51.                 return portalCol;
    52.             }
    53.             ENDCG
    54.         }
    55.     }
    56.     Fallback "Standard" // for shadows
    57. }
    Does anybody know how I could make this work?
     
  2. robochase

    robochase

    Joined:
    Mar 1, 2014
    Posts:
    244
    any luck with this @aNormalGuy ? running into similar issues myself
     
  3. RevCosmosis

    RevCosmosis

    Joined:
    May 21, 2013
    Posts:
    1
    I am having the exact same issue with the exact same prefab. Was able to make SOME headway, but not a complete solution.

    First, add some lines to Portal.cs.
    At the top, define depthTexture:
    Code (CSharp):
    1. // Private variables
    2. RenderTexture viewTexture;
    3. RenderTexture depthTexture;
    In Render(), add SetTargetBuffers():
    Code (CSharp):
    1. for (int i = startIndex; i < recursionLimit; i++) {
    2.             portalCam.transform.SetPositionAndRotation (renderPositions[i], renderRotations[i]);
    3.             SetNearClipPlane ();
    4.             HandleClipping ();
    5.             portalCam.SetTargetBuffers(viewTexture.colorBuffer, depthTexture.depthBuffer);
    6.             portalCam.Render ();
    7.  
    8.             if (i == startIndex) {
    9.                 linkedPortal.screen.material.SetInt ("displayMask", 1);
    10.             }
    11.         }
    In CreateViewTexture, define the depth texture and assign it to the portal material, and also make sure the camera has its depthTextureMode set. (You can change the "16" to change the bit depth of the depth buffer.)
    Code (CSharp):
    1. void CreateViewTexture () {
    2.         if (viewTexture == null || viewTexture.width != Screen.width || viewTexture.height != Screen.height) {
    3.             if (viewTexture != null) {
    4.                 viewTexture.Release ();
    5.             }
    6.             viewTexture = new RenderTexture (Screen.width, Screen.height, 0);
    7.             depthTexture = new RenderTexture(Screen.width, Screen.height, 16, RenderTextureFormat.Depth);
    8.        
    9.             //make sure we have a depth buffer
    10.             portalCam.depthTextureMode = DepthTextureMode.Depth;
    11.             linkedPortal.screen.material.SetTexture("_DepthTex", depthTexture);
    12.  
    13.             // Render the view from the portal camera to the view texture
    14.             portalCam.targetTexture = viewTexture;
    15.             // Display the view texture on the screen of the linked portal
    16.             linkedPortal.screen.material.SetTexture ("_MainTex", viewTexture);
    17.         }
    18.     }
    This is just to make sure there is a depth texture rendered by the camera and sent to the shader.

    Now, to make the shader do something with that depth texture.
    At the top:
    Code (CSharp):
    1. _DepthTex("Depth Texture", 2D) = "white" {}
    Inside the pass:
    Code (CSharp):
    1. sampler2D _DepthTex;
    And then inside of the fragment, where "colCamera" is the color we want to apply fog to:
    Code (CSharp):
    1. fixed4 depthRaw = tex2D(_DepthTex, i.screenPos.xy / i.screenPos.w);
    2. float depthDistance = LinearEyeDepth(depthRaw.r);
    3. UNITY_CALC_FOG_FACTOR_RAW(depthDistance);
    4. colCamera.rgb = lerp(unity_FogColor.rgb, colCamera.rgb, saturate(unityFogFactor));
    What this does is use LinearEyeDepth to compute the physical distance stored in the depth buffer, and then use the UNITY_CALC_FOG_FACTOR_RAW macro to turn that distance into a fog value unityFogFactor, which in turn becomes the factor for a lerp between the base color and fog color.

    (Hopefully I didn't forget anything!)

    Now, does this work? Nope! I am not a shader expert and I'm cobbling together things from examples until I get something that seems close to correct.

    However, it seems to work some of the time. It doesn't seem to render fog most of the time, but the fog suddenly appears once you get very close to the portal. Also, if you have the shader return depthRaw directly instead of the base color, you can see the depth buffer rendered in red coming through. It turns completely black when you get very close - probably somehow related to the fog suddenly appearing. No idea why or how, though!

    Going to continue bashing my head against this until something gives. I'm already using fully custom shaders for everything in my game, so if I can't get this working, I'll see if re-implementing fog via the Catlike Coding tutorial linked below fixes things. (The fog would be "baked" into the color of the material rather than being faded in post... I think? This would also allow me to implement distance-based fog instead of depth-based fog, which would be a great visual improvement.)

    Hope this helps someone! I can feel my brain coming undone.

    EDIT: I can confirm that re-implementing fog as distance-based per the Catlike Coding tutorial works!... as long as you're willing to make custom shaders for literally everything. Worst case scenario, you go without fog on things like trees that use special shaders that I have no idea how to recreate. Also, I am on Built-In Render Pipeline. No idea how any of this translates to URP.

    Sources:
    https://forum.unity.com/threads/converting-depth-values-to-distances-from-z-buffer.921929/
    https://catlikecoding.com/unity/tutorials/rendering/part-14/
    https://forum.unity.com/threads/depth-buffer-and-rendertextures.485675/
     
    Last edited: Dec 4, 2023