Distance Fog Post-Process Material
In this post I will discuss depth (or distance) fog and the things I did to improve on the original basic effect while keeping this simple and light-weight. It’s not a step-by-step tutorial, but explains the core concepts behind the effect including a download link at the end.
Back in the forward rendering days you would get distance fog basically for free in your standard materials (specifically referring to XNA) and now in the age of deferred renderers we have all sorts of different – more advanced – fog types built-in to Unreal (eg. Atmospheric, Exponential Height fog) While those are great for certain types of scenery, I still find myself needing the classic fog style to not only add atmosphere but hide distance gameplay objects or simply focus the players vision more on the near range rather than the horizon. This is there the built-in fog types fail, luckily it’s really easy to build your own.
This type of dense fog can be helpful in optimizing view distances too, where beyond a certain range you cull out objects and no one will notice (I’d suggest to keep the big pieces like towers, terrain etc. that define the fog’s rough horizon) The core implementation of this effect is actually really simple. You check the Scene Depth in your post process and based on that value you interpolate between your original Scene Color and a Fog Color. You now already have your fog material basics completed. The next thing you could do is to add more control over the fall-off by adding Power-node into the graph or adding an offset to the Scene Depth to start the fog beyond the first unit of distance from the camera’s view.
Depth Sampling
There is one problem with this simple implementation however, and that will be apparent when rotating the camera in a scene as near the edges of the camera the fog value is different than the screen center! I’ve seen this happen in older games and was especially apparent in classic World of Warcraft where they had a similar issue with their far plane culling. If you wanted to see what was in the distance, you would simply rotate your camera a bit so you could see the more distant objects near the left or right edge of your screen, which is kind of an useful exploit sometimes, but not desirable in our own games! I’ve added some images with exaggerated fog falloff to clearly demonstrate this edge issue.
For our little fog effect we need something more than a straight forward Scene Depth comparison as the same problem occurs. Instead we use the following:
By using the above we get a consistent density in the fog regardless of the view rotation.
Dynamic Fog Clouds
Now finally I wanted to make the effect slightly more dynamic, by adding clouds. These are not actual volumetric clouds, as that is more expensive and complex to calculate, instead it’s a 3D Perlin noise texture that pans through world-space and is blended into the fog material. The effect doesn’t hold up too well at close range, so it’s only added on the distant pixels of the scene where it looks more believable as ‘volumetric’ clouds.
The clouds are a ‘cheap trick’ and might not work for every style of game. But I think it adds a nice dynamic layer on top of the static distance fog by slightly altering the perceived density at a distance. I’d like to do more experimentation with these clouds as in the current implementation they are barely noticeable and require more work.
I’ve added a download link to the effect, you’ll have to tweak the material to get something that fits your own game the best.
Get Free Access to this and the full Materials Bundle.
Closing
As always you can follow me on Twitter where I tweet about game dev, or subscribe to get updated by new blog posts, tutorials and downloads!
Hey there! I’ve tried out this material, however, whenever I try to blend between post process volumes and the blend weight of the fog material is between 0 and 1, the fog intensity shoots up a lot, making the blending practically useless :P Are there any workarounds?
Unfortunately postprocess fog doesnt affect translucent objects properly (they either get rendered behind or on top of the postprocess depending on the blendable location and/or separatetranslucency settings)
On the contrary, unreal’s fog is implemented at the base shader which allows correct fogging for translucency
Got any workarounds for that?
I don’t quite remember, we ran into this at a later point and I think we did fix it by changing when the fog was rendered – although it was honestly too long ago to clearly remember at this point.
Thanks for the reply
Unfortunatelt I know that alone is not enough. To elaborate on what I said:
– Rendering the fog after translucency makes the translucent stuff (in the postprocess) to have no depth, as if they were an overlay of what’s behind them. So i.e. a smoke column that rises above the horizon will have the land’s depth behind it on its lower part, and the sky’s depth on its upper part. Fog will be totally incorrect.
– Rendering the fog before translucency will make the translucent stuff be completely not affected by the fog at all.
Alternatively you can use the separatetranslucency in the scenecolor node (at the fog postprocess) to differently fake how they are blended, but you still dont get depth so you cant do much except try to color-match a bit
If you did fix this somehow I’d be grateful if you can check
Cheers
Got some very cool mid-range wispy mist by switching to fast gradient noise, but alas getting this to work well with particle translucency is a no-go.. :-( Really wish UE would implement being able to sample the translucency scene color/alpha, looks like that’s still ‘not yet implemented’ in 4.20.3.
Thank you
Hi Tom, I love the effect! Another great use of this material would be to generate a “fade to black” effect for distant objects. I think that this + distance occlusion would be great for mobile performance (as mobile doesn’t have hardware occlusion), but for some reason I can’t get this material to work in android.
The material works but without any depth calculations (The same fog opacity is applied to the entire viewport). I tried changing the “Scene Depth” node for another one made with “AbsoluteWorldPosition”, “CameraPostion” and “Distance” and it works fine in PC but doesn’t work at all in android.
Any ideas? Thank you!
Apparently, it is related to using MSAA. It does work when using FXAA, which is quite crappy in comparison.
Would you know of any workarounds for this? It might be related to how SceneDepth is calculated while using MSAA:
https://answers.unrealengine.com/questions/530926/msaa-not-working-with-custom-post-processing-custo.html
Do you have project files for 4.18?
I don’t have that, you can open it in 4.19 and copy the material graph back into your 4.18 project though.
– Tom
Great, thanks Tom.
Tom can I ask you about AI?
Thanks for this one Tom!
I have a question that might be something you have thought about before, similar to your “experiments” (but unrelated to this ;)
Would it be possible to make a function that sits inside a masked “interface” material, that creates a fake glow / or drop shadow? So given a mask, it would create a gradient out that can be combined back into the base and the opacity mask.
Is that something you think would even be technically possible? Just an idea i had but im unsure on how you would achieve that…
Cheers