Clustered Forward Shading for Dense Lights in glTF
Clustered forward shading efficiently renders scenes containing thousands of dynamic light sources by subdividing the camera frustum into a three-dimensional grid of spatial clusters and assigning active lights to these volumes. When paired with complex glTF environments—which frequently feature intricate asset hierarchies, diverse physically based rendering (PBR) materials, and varying alpha-blending modes—this approach eliminates the traditional performance bottlenecks of standard forward and deferred rendering. By evaluating only the lights that intersect each fragment’s specific spatial cluster, the engine maintains high frame rates, full support for transparent surfaces, and minimal memory overhead regardless of light density.
The Problem with Traditional Forward and Deferred Pipelines
Standard forward rendering evaluates every active light against every rendered primitive, resulting in an algorithmic complexity of \(O(\text{geometry} \times \text{lights})\). In dense scenes, this causes severe shader bloat and heavy fill-rate penalties.
Deferred shading decouples lighting from geometry by writing surface properties to a G-buffer. While it handles high light counts well, it struggles with the standard features native to glTF 2.0. Deferred pipelines cannot natively handle transparent materials, struggle with multi-material shading variations (such as glTF extensions for clearcoat, transmission, and sheen), and require high memory bandwidth for wide G-buffers, making them less ideal for complex asset pipelines.
How Clustered Shading Operates
Clustered shading resolves these trade-offs by partitioning the view frustum along three axes:
- Frustum Subdivision: The screen is divided into a 2D tile grid (typically \(16 \times 16\) pixels), and the view depth is divided logarithmically into slices along the Z-axis. This forms a 3D grid of sub-frusta known as clusters.
- Light Cull and Binning: A compute shader tests the bounding volumes of all scene lights (point lights, spot lights) against the bounding boxes of these 3D clusters.
- Index Generation: The engine builds a flat global list of light indices and a per-cluster lookup table (offset and count).
- Per-Fragment Shading: During the standard forward
rendering pass, a fragment shader calculates its 3D cluster coordinate
directly from
gl_FragCoord.xyand linear view depth. It then loops exclusively over the lights mapped to that cluster.
Because the depth slicing is logarithmic, near-plane clusters remain tight while far-plane clusters encompass larger volumes, balancing light distribution across depth.
Managing Complex glTF Asset Features
glTF models often combine complex node hierarchies, multiple mesh primitives, and rich material models. Clustered forward shading accommodates these structures directly:
- Material Diversity: glTF files can mix standard PBR metallic-roughness workflows with extensions such as KHR_materials_transmission, KHR_materials_ior, and KHR_materials_volume. Because clustered rendering executes in a forward pass, distinct shaders can evaluate unique material properties per draw call without the uniform material restrictions of a G-buffer.
- Alpha Blending and Transparency: Translucent
objects, foliage, and glass elements defined by glTF alpha modes
(
BLENDandMASK) sample the same cluster grid as opaque geometry. This allows dense lighting to interact accurately with transparent surfaces in a single pass without secondary lighting passes. - Depth Discontinuities: Unlike 2D tiled forward shading—where a light far behind a foreground edge lights both surfaces because they share a 2D screen tile—clustered shading isolates objects along the Z-axis. Meshes with high geometric depth variation, such as dense architectural or industrial glTF scenes, do not suffer from false light allocations.
Performance Scaling Under High Light Counts
By restricting light iteration to localized 3D volumes, clustered forward shading bounds the inner loop of the fragment shader. Even in environments with thousands of point lights placed throughout a complex glTF world, any single fragment typically processes only 5 to 50 active lights. The compute overhead for building the cluster grid scales with the number of lights and clusters rather than scene geometric complexity, providing predictable frame times across varying hardware profiles.