Thx for reply Remy. In hindsight that might be a better approach. 
I just got the post process shader working though, after 5+ hours of debugging with google gemini AI. Here are the instructions for anyone wanting to recreate this in BIRP.
- Add the following script to your camera gameobject.
using UnityEngine;
public class ExponentialFogEffect : MonoBehaviour
{
public Material fogMaterial;
[Range(0, 1)]
public float fogDensity = 0.05f;
[Range(0, 500)]
public float startDistance = 20f;
public Color fogColor = Color.white;
private Camera cam;
void Start()
{
cam = GetComponent<Camera>();
}
void OnRenderImage(RenderTexture source, RenderTexture destination)
{
fogMaterial.SetFloat("_FogDensity", fogDensity);
fogMaterial.SetFloat("_StartDistance", startDistance);
fogMaterial.SetColor("_FogColor", fogColor);
fogMaterial.SetVector("_CameraPosition", cam.transform.position);
Graphics.Blit(source, destination, fogMaterial);
}
}
- Create the following shader.
Shader "Hidden/ExponentialFog"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_FogColor ("Fog Color", Color) = (0.5, 0.5, 0.5, 1)
_FogDensity ("Fog Density", Range(0, 1)) = 0.05
_StartDistance ("Fog Start Distance", float) = 20.0
}
SubShader
{
Cull Off ZWrite Off ZTest Always
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float2 uv_depth : TEXCOORD1;
};
sampler2D _MainTex;
sampler2D _CameraDepthTexture;
float3 _CameraPosition;
float _FogDensity;
float _StartDistance;
fixed4 _FogColor;
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.uv_depth = v.uv;
return o;
}
// A helper function to get the world position
float3 GetWorldPos(float2 uv)
{
float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv);
float linearDepth = LinearEyeDepth(depth);
float3 viewRay = mul(unity_CameraInvProjection, float4(uv * 2 - 1, 1, 1));
float3 viewPos = viewRay * linearDepth;
float4 worldPos = mul(unity_CameraToWorld, float4(viewPos, 1));
return worldPos.xyz;
}
fixed4 frag (v2f i) : SV_Target
{
float3 worldPos = GetWorldPos(i.uv_depth);
float dist = distance(worldPos.xyz, _CameraPosition);
// Calculate exponential fog. It is always active but fades in.
float exponentialFog = 1.0 - exp(-dist * _FogDensity);
// Blend in the fog after the start distance.
// We use a linear ramp, but a small blend zone could be added for a smoother transition.
float startFade = saturate((dist - _StartDistance) / 10.0);
// Combine the effects
float fogAmount = exponentialFog * startFade;
fixed4 originalColor = tex2D(_MainTex, i.uv);
return lerp(originalColor, _FogColor, fogAmount);
}
ENDHLSL
}
}
}
-
Create a material and set it to the shader.
-
Set the material to the “fogMaterial” in the script on your camera.
-
Set the fog start, density, color, etc, in the camera script.
I’ve noticed that it doesn’t play nice with the post process stack anti aliasing though, there is some jitter going on and there might be some conflicts with the other post processing effects so it might be best to try Remys method.
Also make sure your camera near plane is at least 0.1 or the camera depth texture doesn’t get generated correctly.
I’ve got to say… I’m impressed with the google AI. It gave me code that didn’t work a couple of times but I kept asking it to give me variations and eventually it gave me snippets that worked here and there. It told me how to debug the shaders and it explained what every line does so I feel like I learned a lot and saved myself 20 hours of headache. I couldn’t have done it without 
EDIT: I tried your method Remy but SSAO displays on top of it. I think I’ll just use the post process shader and switch to FXAA aliasing instead of TAA. I tried creating a custom post processing V2 stack shader and it worked but I couldn’t figure out where/how to tie it into the TAA code to stop the jittering.