Creating Volumetric Fog and Clouds in Game Development
Volumetric fog and clouds are essential elements in modern game development, providing depth, realism, and atmosphere to virtual environments. This article explores the technical process of creating these dynamic atmospheric effects, detailing how developers utilize raymarching, 3D noise generation, light scattering physics, and optimization techniques to render realistic volumetric systems in real-time.
The Foundation: Raymarching
Unlike traditional flat 2D billboards or particle effects, volumetric rendering requires calculating depth. The primary technique used is raymarching, which is executed within a fragment shader.
For every pixel on the screen, the engine casts a virtual ray from the camera into the game scene. The shader steps along this ray at set intervals (samples), checking the density of the fog or cloud medium at each point. By accumulating these density samples, the engine determines how much light is absorbed, scattered, or transmitted through the volume before it reaches the camera.
Defining Shape with 3D Noise
To prevent volumetric structures from looking like uniform, solid blocks, developers use 3D noise functions to define their shape and density.
Typically, a combination of Perlin noise and Worley noise is pre-calculated and stored in a 3D texture. Perlin noise provides the organic, soft structures of the clouds or fog, while Worley noise is used to carve out tight, billowy, “wispy” details along the edges. By shifting these noise textures over time using wind vectors, developers create the illusion of evolving, drifting clouds and rolling fog.
Simulating Light Transport
To make the volumes look realistic, the shader must calculate how light interacts with the particles. This involves calculating two main components:
- Out-Scattering and Absorption: As light travels through the volume, some of it is absorbed by the particles or scattered away from the camera. This reduction in light intensity is calculated using the Beer-Lambert Law.
- In-Scattering: This occurs when light from the sun or local light sources enters the volume, bounces off the particles, and is redirected toward the camera. Developers use the Henyey-Greenstein phase function to simulate this, which dictates how light scatters forward or backward depending on the angle between the light source, the particle, and the camera.
Performance and Optimization
Rendering volumetric effects is computationally expensive because raymarching requires dozens of samples per pixel. To achieve playable frame rates in modern games, developers rely on several optimization strategies:
- Downsampling: Volumetric effects are often rendered at a lower resolution (such as quarter or half resolution) and then upscaled to match the screen resolution using bilateral filtering to preserve sharp edges.
- Temporal Reconstruction: Instead of sampling the entire volume every frame, engines use temporal anti-aliasing (TAA) techniques to jitter the sample positions and accumulate the data over multiple frames, significantly reducing the sample count per frame.
- Shadow Maps and Lodding: Engines use deep shadow maps or voxelized light grids to quickly lookup shadow data, and implement Level of Detail (LOD) systems that reduce raymarching steps for volumes that are far away from the player.