Skip to main content

Light Propagation Volume (Experimental)

DEMO

This page covers the Light Propagation Volume (LPV) implementation.

LPV is a fully dynamic, compute-driven global illumination approximation built around one or more 32×32×32 light volumes centred ahead of the view. It injects scene geometry, directional light, and optional local lights into volume textures, propagates the stored lighting through neighbouring cells, then applies the result back to the scene as indirect diffuse lighting with optional LPV specular approximation. True light bounce / secondary re-injection is not present in this version; a cheaper bounce-lighting path is actively being researched.

Prerequisite

LPV only runs when the project uses the Global Illumination Plugin path in Project Settings and rEx.GI.Method=1.

Forward Rendering Limitations

The forward path is more limited than deferred because it has depth-only geometry injection and no full GBuffer material data. LPV forward rendering also does not work correctly with MSAA 2x or higher, so use deferred rendering for production LPV testing.


Overview

The LPV pipeline runs in several compute stages each update:

  1. Cascade setup
    One to four 32×32×32 cascades are positioned ahead of the camera. Each cascade has its own world-space size.

  2. Geometry injection
    Scene geometry is injected into a geometry volume from scene depth and GBuffer data in deferred rendering. The forward path uses depth-only geometry injection.

  3. Geometry volume build
    The injected geometry list is converted into a low-frequency 3D occlusion volume used during light injection, propagation, and apply.

  4. Direct light injection
    The main directional light injects radiance into the LPV. Point and spot lights can also inject into the best matching ready cascade when local-light injection is enabled.

  5. Propagation
    Light energy is propagated through neighbouring cells for a configurable number of iterations.

  6. Scene apply
    The propagated LPV is sampled in screen space and added as indirect lighting. Higher quality levels use improved diffuse reconstruction and optional cone-traced LPV specular.

LPV is a coarse dynamic GI approximation. It is useful for broad ambient fill and colour bleeding, not for physically accurate bounce lighting.

Current Behaviour Notes

  • LPV respects Post Process IndirectLightingIntensity as the final scalar multiplier.
  • LPV does not use Post Process IndirectLightingColor.
  • Cascaded LPV is now implemented through multiple independent 32³ volumes.
  • Local point and spot light injection is available and can be disabled with rEx.LPV.EnableLocalLights=0.
  • Forward rendering has a dedicated path, but it is more limited than deferred because it does not have full GBuffer material data.

Forward Rendering

Forward LPV should be treated as a limited compatibility path. It uses scene depth for geometry injection, so it cannot reconstruct the same material and normal information available in deferred rendering. This makes occlusion, leakage control, and final shading less reliable than the deferred path.

Forward LPV also does not work correctly with MSAA 2x or higher. If the project uses MSAA, disable LPV or switch to deferred rendering for LPV validation.


Console Variables

GI Method

rEx.GI.Method (int, default: 0)
Selects the active GI implementation.

  • 0 — Disabled.
  • 1 — Light Propagation Volume.

Core LPV Settings

rEx.LPV.Size (float, default: 5312.0)
World-space size of the largest LPV cascade. Larger values cover more area but reduce detail per cell.

rEx.LPV.FadeRange (float, default: 6.0)
Number of grid cells near a cascade boundary used for fade-out.

rEx.LPV.PropagationWeight (float, default: 0.01)
Per-neighbour propagation strength. Higher values spread light faster but increase leaking risk.

rEx.LPV.PropagationIterations (int, default: 4)
Number of propagation iterations per full LPV update.

rEx.LPV.UpdateInterval (int, default: 2)
Frames between full LPV updates. 0 updates every frame; higher values reuse the previous result longer.


Cascades

rEx.LPV.NumCascades (int, default: 3, range: 1–4)
Number of active LPV cascades.

rEx.LPV.CascadeRatio (float, default: 2.0)
Size divisor between cascades. Higher values make inner cascades smaller and denser.

rEx.LPV.AutoCascadeMinSize (float, default: 768.0)
If greater than 0, automatically increases the cascade ratio so the smallest cascade is roughly this size.

rEx.LPV.CascadeForwardOffset (float, default: 0.35)
Moves cascade centres forward along the camera direction as a fraction of cascade size.


Lighting

rEx.LPV.EnableLocalLights (int, default: 1)
Enables point and spot light injection into LPV cascades. 0 clears local-light volumes and uses directional light only.

rEx.LPV.LogLocalLights (int, default: 0)
Logs how many cached local lights were accepted for LPV injection.


Quality

rEx.LPV.Quality (int, default: 1)
LPV quality preset.

  • 0Linear SH diffuse only. Samples the LPV linear spherical-harmonic data and applies it as diffuse indirect lighting. Cheapest path, lowest reconstruction quality, no advanced leak dampening, no specular.
  • 1ZH3 + HLSH diffuse. Adds hallucinated ZH3 / HLSH diffuse reconstruction and directional derivative leak dampening. Recommended default because it improves diffuse shape and reduces obvious leaking without enabling specular tracing.
  • 2ZH3 + HLSH diffuse + cone-traced LPV specular. Keeps Quality 1 diffuse features and adds approximate specular by cone tracing through the LPV volume. Most expensive path and still approximate; it is not a replacement for SSR, reflection captures, or ray-traced reflections.
No True Light Bounce

Current LPV propagation spreads injected light through the volume, but this version does not implement true light bounce / secondary surface re-injection. A cheaper bounce-lighting method is actively being researched.

rEx.LPV.ConeTraceSamples (int, default: 6)
Number of samples used by LPV cone-traced specular in Quality 2. Typical values: 4 short range, 6 balanced, 8 longer range.


Debug

rEx.LPV.DebugViz (int, default: 0)
LPV debug visualisation mode.

  • 0 — Off.
  • 1 — LPV cascade 0 only.
  • 2 — Geometry volume cascade 0 only.
  • 3 — AO from geometry volume cascade 0 only.
  • 4 — LPV all cascades.

Practical Guidance

Choosing Cascade Count

Use rEx.LPV.NumCascades=1 for the cheapest result. Use 2–3 cascades when you need both wide coverage and better detail near the camera. 4 cascades is the most expensive and should be reserved for testing or high-end targets.

Choosing LPV Size

rEx.LPV.Size controls the largest cascade. A large size improves outdoor coverage but makes each 32³ cell coarse. A small size gives cleaner local bounce but fades out sooner.

Choosing Quality

  • Quality 0 is the cheapest diffuse-only path.
  • Quality 1 is the recommended default because it improves diffuse reconstruction without enabling specular trace cost.
  • Quality 2 adds cone-traced LPV specular and should be treated as experimental.

When LPV Works Well

LPV works best for broad ambient fill, subtle colour bleeding, soft dynamic bounce, and stylised scenes that do not require precise GI.

LPV works poorly for thin-wall interiors, precise occluded bounce, small geometric detail, glossy accuracy, and scenes where 32³ volume resolution is visibly too coarse.


Known Limitations

  • Low spatial resolution — every cascade is still 32³, so leakage and coarse blocking are fundamental.
  • Approximate cascades — cascades improve coverage/detail balance but do not make LPV physically accurate.
  • Specular is approximate — Quality 2 samples LPV radiance, not real reflections.
  • Local lights are filtered — only cached point and spot lights that affect GI, intersect a ready cascade, and are large enough for the cascade cell size are injected.
  • Not physically correct — LPV propagation is an artistic dynamic GI approximation, not path-traced bounce lighting.
  • No true light bounce yet — current propagation spreads injected lighting, but secondary bounce / surface re-injection is not implemented in this version.
  • Forward path is limited — it relies on depth-only geometry injection and has worse material awareness than deferred.
  • Forward + MSAA is unsupported — MSAA 2x and above do not work correctly with the current forward LPV path.