Changing Unity´s fog (realistic fog)

Hey folks,
I´m currently working on an image effect shader that should modify Unitys normal fog.
My problem is that I have a dark scene with many lightsources. The fog lights up the whole scene and is applied everywhere. But it´s more realistic that everything get´s a little darker and you can only see the fog where light is. (see pic)

Do you have an idea how to solve this problem and apply it so and image effect shader? :slight_smile:

Here is what I tried. Whole idea: the brighter the background the more fogcolor I want to add.
Fog absorbs light so must the scenecolor (b) the highest value. The darker “b” gets the more would fog darken it. On the other hand will a bright “b” not get darkend much by a bright “a”.

            fixed4 frag (v2f i) : SV_Target
            {
                float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);    //get depth-information from the CameraDepthTexture for the current fragment
                depth = Linear01Depth(depth);    //raw-data are lon-linear values 0-1. We want to convert them to linear values
                float viewDistance = depth * _ProjectionParams.z -_ProjectionParams.y; //scale by the parameter "far clip plane" distance (also Sichtweite der Kamera)
                //subtract the near clip plane

                UNITY_CALC_FOG_FACTOR_RAW(viewDistance); //calculated fog-density and stores value in unityFogFactor
                unityFogFactor = saturate(unityFogFactor);    //need to be clamped to 0-1
               
                float3 b = tex2D(_MainTex, i.uv).rgb;
                float3 a = unity_FogColor;   
                float w = unityFogFactor;
                float3 foggedColor = float3(1,1,1);
               
                float3 diff = sqrt( pow( b-a, 2));
                b = b - diff;
                a = a - diff;
                foggedColor = saturate(lerp(a,b,1-w));

                float4 finalColor = float4(foggedColor, 1);
                return finalColor;
            }

Without Shader:

With Shader:

1 Like

Update: I tried a different approch (seventh try).
Normally Unity calculates fog usig lerp(a,b,w) like this

float3 b = tex2D(_MainTex, i.uv).rgb;
                float3 a = unity_FogColor;   //Color which is set in Lighting tab
                float w = unityFogFactor;    //calculated from distance
                float3 foggedColor = float3(1,1,1);
                float3 foggedColor = lerp(a,b,w);
return foggedColor

Now I had the idea to lerp two times. (See code below) First I lerp between the fogColor (a) and background color (b) and us as weight “b”. The darker (low value) the more it will mix the Color toward the backgroundcolor (b), which means that a dark area will have a dark color as result (new_a). This is my new fogcolor for this special pixel. The second time I lerp the neu fogcolor (new_a) with b, based on the distance (w), just like Unity does it normally. In theory it should apply more fog to lighter areas and less fog to darker areas. It works, yes. But there is no “depth”-fog as you may see in the pictures.

fixed4 frag (v2f i) : SV_Target
            {
                float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);    //get depth-information from the CameraDepthTexture for the current fragment
                depth = Linear01Depth(depth);    //raw-data are lon-linear values 0-1. We want to convert them to linear values
                float viewDistance = depth * _ProjectionParams.z -_ProjectionParams.y; //scale by the parameter "far clip plane" distance (also Sichtweite der Kamera)
                //subtract the near clip plane

                UNITY_CALC_FOG_FACTOR_RAW(viewDistance); //calculated fog-density and stores value in unityFogFactor
                unityFogFactor = saturate(unityFogFactor);    //need to be clamped to 0-1
               
                float3 b = tex2D(_MainTex, i.uv).rgb;
                float3 a = unity_FogColor;   
                float w = unityFogFactor;
                float3 foggedColor = float3(1,1,1);
               
                float3 new_a = lerp(b,a,b*4);
                foggedColor = lerp(new_a,b,w);
               
                float4 finalColor = float4(foggedColor, 1);
                return finalColor;
            }
            ENDCG

Scene without fog shader

Current shader: (fog is red for visualisation) It gets applied more to areas where light is, but there no denser-getting fog in the distance

Unitys standard fog via lerp

1 Like

The way this is usually handled for games from 5+ years ago was to use black fog and to manually place effects around lights to make them glow. Something like this asset:

Modern games use real volumetric fog calculations. Unity’s HDRP has this built in, but for other renderers you could use this asset:

Thanks for the hint. Unfortunely I have to create my own shader since it´s a task for university. That´s why buying an asset is not an option :confused: I need to solve this problem in someway

1 Like

Thanks for the link, I´ll read it. So you´d say a volumetric approach is the better solution?

Define better?

Is the volumetric approach more realistic and less manual work to have it interact properly with arbitrary scenes? Yes. Much, much more expensive to render, and significantly more code to implement? Also yes.

Sticking a cone mesh with an view angle and distance fading shader on each light is a ton less work overall for a single scene.

1 Like