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?
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;
}
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
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 I need to solve this problem in someway
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.