Render texture with depth for default fog issue

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:

// Private variables
RenderTexture viewTexture;
RenderTexture depthTexture;

In Render(), add SetTargetBuffers():

for (int i = startIndex; i < recursionLimit; i++) {
            portalCam.transform.SetPositionAndRotation (renderPositions[i], renderRotations[i]);
            SetNearClipPlane ();
            HandleClipping ();
            portalCam.SetTargetBuffers(viewTexture.colorBuffer, depthTexture.depthBuffer);
            portalCam.Render ();

            if (i == startIndex) {
                linkedPortal.screen.material.SetInt ("displayMask", 1);
            }
        }

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.)

void CreateViewTexture () {
        if (viewTexture == null || viewTexture.width != Screen.width || viewTexture.height != Screen.height) {
            if (viewTexture != null) {
                viewTexture.Release ();
            }
            viewTexture = new RenderTexture (Screen.width, Screen.height, 0);
            depthTexture = new RenderTexture(Screen.width, Screen.height, 16, RenderTextureFormat.Depth);
        
            //make sure we have a depth buffer
            portalCam.depthTextureMode = DepthTextureMode.Depth;
            linkedPortal.screen.material.SetTexture("_DepthTex", depthTexture);

            // Render the view from the portal camera to the view texture
            portalCam.targetTexture = viewTexture;
            // Display the view texture on the screen of the linked portal
            linkedPortal.screen.material.SetTexture ("_MainTex", viewTexture);
        }
    }

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:

_DepthTex("Depth Texture", 2D) = "white" {}

Inside the pass:

sampler2D _DepthTex;

And then inside of the fragment, where “colCamera” is the color we want to apply fog to:

fixed4 depthRaw = tex2D(_DepthTex, i.screenPos.xy / i.screenPos.w);
float depthDistance = LinearEyeDepth(depthRaw.r);
UNITY_CALC_FOG_FACTOR_RAW(depthDistance);
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: