For anyone who has this same problem (needing to get clip space Z value only from depth), I managed to stumble across a random github repo that had the solution:
https://github.com/h33p/Unity-Graphics-Demo/blob/master/Assets/Standard Assets/Effects/ImageEffects/Shaders/GlobalFog.shader
https://github.com/h33p/Unity-Graphics-Demo/blob/master/Assets/Standard Assets/Effects/ImageEffects/Scripts/GlobalFog.cs
These are old, but the math is the same for the most part. The part that was needed was from that shader; “ComputeDistance()”
I ported the relevant pieces over, including the camera frustum corners, but it turns out they weren’t needed for URP fog. (You can do that part in shader graph by copying the relevant C# portion to set the material matrix4x4, then in Shader Graph, use a custom function node and put it into a custom interpolator on the vertex output.) Those were needed for radial distance, but to my eye, the non-radial distance calculation matches the URP fog perfectly, even in extreme scenarios.
URP - NearPlane: 0.1, FarPlane: 100, Fog: exp2 0.03
Shader graph ComputeFogValue_float custom function output:
I removed all of the frustum corner code and now my custom HLSL is very clean and concise:
EDIT: I added a max(0,x) here since URP does it in shadergraph_LWFog (ShaderGraphFunctions.hlsl)
float GetClipZ_01(float linearDepth, float nearPlane, float farPlane)
{
return max(0, (linearDepth * farPlane) - nearPlane); // Non-radial distance
}
You can get the nearPlane and farPlane value from the Camera Node, and the linearDepth from the Scene Depth Node. The output shader graph simply uses this:
void ComputeFogValue_float(float linearDepth, float nearPlane, float farPlane, out float fogFactor)
{
float clipZ_01 = GetClipZ_01(linearDepth, nearPlane, farPlane);
fogFactor = ComputeFogIntensity(ComputeFogFactorZ0ToFar(clipZ_01));
}
void ComputeFogColor_float(float3 mixColor, float linearDepth, float nearPlane, float farPlane, out float3 fogFactor)
{
float clipZ_01 = GetClipZ_01(linearDepth, nearPlane, farPlane);
fogFactor = MixFog(mixColor, ComputeFogFactorZ0ToFar(clipZ_01));
}
You can use either of those two functions. MixFog calls ComputeFogIntensity() for you. Custom Function nodes also include the relevant URP .hlsl files so you don’t have to (I mentioned in the first post that I was, but this caused duplicate include warnings, and it turns out I didn’t need them). The first of these two functions will just show the fog in black/white if you output that to your shader graph. That’s how I was able to see that the GetClipZ_01() was working perfectly, even in extreme cases, like when nearPlane is 16.5 etc.
URP - NearPlane: 16.5, FarPlane 100, Fog: exp2 0.19
Shader graph ComputeFogValue_float custom function output:
Even if they don’t match 100%, nobody would notice a difference in-game. I’m using this solution so I wanted to help anyone who may have the same situation. It’s better than being being forced to use multiple render-targets like I was before. Now I can just use the depth from the previous renders instead of outputting the fog density to a separate texture