Hey everyone!
I built a GPU-friendly, height-based ground fog system for Three.js, designed for real-time games and FPS-style movement. It uses multi-octave FBM noise for subtle drifting effects, while staying extremely fast, even with instanced geometry and shadows.
Features:
-
Fog intensity based on world Y coordinate (height-only).
-
FBM noise for natural turbulence and drifting motion.
-
Works on instanced meshes with minimal overhead.
-
Configurable: fog height, depth, opacity, noise, wind, and vertical billow.
-
Fully compatible with standard Three.js lights and shadows.
Performance Notes:
-
Cheap enough for real-time games.
-
Reduce noise octaves or opacity for tighter budgets.
-
Only patch materials that need fog to save shader compile time.
Inspired by SimonDevs’ procedural fog experiments and Ashima/Stegu noise.
Live Demo on CodePen →
12 Likes
This is pretty cool.. but I noticed its hard to get some of the turbulent flowing effect of the fog.. when I cranked some values, is see that the noise layers are heavily quantized.. is this by design? I feel like you could get better/organic details with a less posterized noise?
@manthrax Thanks for pointing that out. I hadn’t noticed it until you mentioned it.The noise layers themselves are continuous. The posterization comes from how the noise strength is applied: at full strength the multiplier ranges from 0.0 to 2.0, so the fog density can be scaled down to nothing or up to double. That’s why cranking the slider looks quantized. I’ve remapped it so the 0-1 slider corresponds to a much smaller effective swing (+/-5%), which keeps the turbulence organic and flowing
// modulate fog by noise strength (remapped)
float effectiveStrength = uNoiseStrength * 0.05; // remap 0–1 → 0–0.05
float noiseMod = mix(1.0 - effectiveStrength, 1.0 + effectiveStrength, n01);
float fogFactor = clamp(heightAtten * noiseMod * uFogOpacity, 0.0, 1.0);
I also bumped the max octaves from 5 to 8, which gives finer FBM detail. Together, these changes keep the fog looking a bit more “natural”.
Thanks again!
1 Like
its very taxing on the cpu, on mobile it is almost in complete freeze, it’l be awesome to have fog on large scale environment, but this takes away the experience more than it benefits.
Hi @Umbawa_Sarosong,
Thanks for letting me know. This is highly unusual (and interesting) for a few reasons:
-
This code is GPU-bound, not CPU-bound.
-
I’m seeing constant 60 FPS (device max) on a 6-year-old iPhone, among other test devices, all running at their maximum theoretical FPS.
I’ve added the stats-gl module to the CodePen for easier debugging. I also added two new controls:
Additionally:
Could you do me a favor and experiment with the radius and shadow settings, and report back? If possible, please specify exactly what hardware you’re using.
I’ve reviewed the shader closely and just can’t identify anything that would kill the CPU this badly. If your phone is still struggling, I’ll take an even closer look at the shader and see what can be optimized.
Thanks so much!
Great job @red-reddington! Exactly what I needed for my game quite some time ago. Now I know I can get back to your demo if I decide to improve it one day.

1 Like