Hybrid SDF GI
Hybrid SDF GI is the software global illumination technology used by XFSDK Core and XFSDK Light. It uses Unreal's global distance field, probe volumes, a surfel cache and an optional final gather; hardware ray tracing and lightmaps are not required for this documented mode.
XFSDK Core and the standalone XFSDK Hybrid SDF GI use the x_ console-variable prefix; XFSDK Light uses xl_. For the shared GI settings, only the prefix changes.
Console variable naming
For the shared GI implementation, Core and standalone GI use x_, while Light uses xl_. The suffix, meaning and parameter values are unchanged.
| XFSDK Core / Standalone GI | XFSDK Light |
|---|---|
x_gi_method=2 | xl_gi_method=2 |
x_gi_dfgi_lite_quality=1 | xl_gi_dfgi_lite_quality=1 |
x_gi_dfgi_lite_final_gather=1 | xl_gi_dfgi_lite_final_gather=1 |
Core examples below use x_. To use the same GI parameter in Light, replace that prefix with xl_. This rule does not apply to Light-only Bend screen-space shadows (xl_sss_*).
How it works
The GI is built from four parts. Each one answers what the previous one can't.
- GI volumes (probes). You place volumes in the level. Each fills its box with a regular grid of probes, like NVIDIA's DDGI. Every frame, the probes that visible pixels used on the previous frame cast rays through the global distance field, and a rolling budget refreshes the rest of the volume. Each probe stores the light arriving from all directions plus how far it can see, so light does not leak through walls. Probes stuck inside geometry are moved out or switched off automatically.
- Surfel cache. When a probe ray hits a surface, the GI needs that surface's color and lighting. The distance field only knows shape, so The implementation places small disks (surfels) on surfaces the camera has seen, records their material and lighting from the GBuffer, and probe rays read them. This is where emissive light comes from.
- Per-pixel lighting. Each pixel blends the nearest probes, weighted by distance and visibility, and adds the result as indirect diffuse light. Pixels outside every volume get sky light only.
- Final gather (optional). Probes are 2 m apart by default, so they miss small detail: the dark gap under a rock, light bouncing off a nearby emissive object. The final gather traces one short ray per pixel to fix that up close. It follows the approach id Software presented for DOOM: The Dark Ages.
Quick start
- Enable mesh distance fields and configure the GI integration required by your product; restart the editor if those project settings change. See Light configuration for Light; Core and standalone installation settings are not supplied here.
- Place an XFSDK GI Volume actor (Place Actors panel, search "XFSDK GI Volume") and scale its box over the playable area. Use several volumes for large or multi-room levels.
- Look around: probes converge over a few seconds. Use
x_gi_dfgi_lite_visualize 3to see them. - Optionally press Bake GI on the volume to freeze it. See Baking.
Keep a Sky Light in the level. Its lighting feeds the GI's sky rays and lights pixels outside every volume. If the image looks noisy, check the Sky Light's cast shadows first: in testing it was the main source of noise, not the GI.
GI volumes
| Property | Default | Description |
|---|---|---|
| Probe Spacing | 200 cm | Distance between probes. Denser volumes catch smaller occluders and cost more. |
| Priority | 0 | Where volumes overlap, higher priority wins. Equal priority prefers the denser volume. |
| Blend Distance | 800 cm | The volume fades in over this distance from its edge, so neighbouring volumes blend smoothly. |
| Blend Cutoff Distance | 0 cm | Zero weight this close to the edge, before the fade starts. |
| Enable Volume | true | A disabled volume neither lights nor updates. |
| Update Priority | 1.0 | This volume's share of the probe update budget compared to other live volumes. |
| Probe Max Ray Distance | 100000 cm | Shorter rays are faster but miss far occluders and see more sky. Rebake after changing. |
| Normal Bias | 0.05 | Moves the lookup off the surface (fraction of probe spacing). Fixes self-shadowing. |
| View Bias | 0.2 | Moves the lookup towards the camera (fraction of probe spacing). Reduces leaks and dark bands. |
| Light Multiplier | 1.0 | Scales this volume's indirect light. Does not change baked data. |
| Update Mode | Baked | How the probes stay current. See Update modes. |
| Update Interval | 4 | Delayed only: frames between traces of each visible probe (2–16). |
| Start From Bake | true | Responsive and Delayed only: start from the volume's bake when it has a valid one, instead of from black. |
Size limits. A volume holds up to 128 probes per axis and 262,144 probes in total. If a box needs more, the spacing widens automatically so the whole box stays covered, and the log reports the spacing actually used. Split very large areas into several volumes to keep the density you want.
Run x_gi_dfgi_lite_list_volumes to log every volume: enabled, registered, size, probe grid, update mode and bake state.
Update modes
| Mode | Behaviour |
|---|---|
| Responsive | Probes the visible pixels use are traced every frame, so moving lights and emissive objects are followed within a few frames. The rest of the volume updates on the rolling budget. |
| Delayed | Like Responsive, but each visible probe is traced every Update Interval frames, staggered across probes. Costs 1/N as much; lighting changes fade in over up to 8 × N frames. |
| Baked | Uses the baked probes and never traces. Without a valid bake the volume runs Responsive, so it can be baked. |
Volumes saved before Update Mode existed are converted on load: Use Bake If Available becomes Baked, and Keep Updating (Warm Start) becomes Responsive with Start From Bake on.
Baking
A volume with Update Mode Baked and a valid bake stores its probes in the level and stops updating: no probe rays, no surfels. It is the cheapest way to run the GI, and the right choice for static lighting. Responsive and Delayed volumes can use their bake as a starting point (Start From Bake).
- Keep the editor viewport camera inside or near the volume, with
x_gi_method 2. - Press Bake GI on the volume (or run
x_gi_dfgi_lite_bake_volumesto bake every volume that is not already frozen). Baking keeps the volume's Update Mode. - Wait until the log reports the bake (
LogXFSDKGI, "[GI Volume]"), then save the level.
Things to know:
- One bake covers every quality level and the final gather. Quality and final gather work on top of the probes at runtime.
- Probes learn material colors and emissive light from surfels, which come from what the camera has seen. Look around the volume while it bakes, especially at emissive objects, or their light will be missing from the bake.
- A bake goes stale when the volume moves or its box or probe spacing changes; the volume then runs live until you rebake. Rebake by hand after changing lights, geometry or Probe Max Ray Distance. Clear Baked GI removes it. A frozen (Baked) volume can't be rebaked in place: clear its bake or switch it to Responsive first.
- Bakes are stored as compact half-float binary data.
Quality
Each level adds to the previous one.
x_gi_dfgi_lite_quality | Adds |
|---|---|
0 Low | Per-probe linear spherical harmonics. Cheapest. |
1 Medium (default) | Smoother probe blending, deringing, and ZH3 reconstruction for better contrast. |
2 High | Distance-field cone occlusion below probe resolution (as in UE4's DFGI). |
3 Epic | Rough specular from the probes, fading in above x_gi_dfgi_lite_specular_min_roughness (0.35). |
Final gather
x_gi_dfgi_lite_final_gather=1
Every pixel traces one short ray (3 m by default) through the distance field. The hit is shaded from last frame's screen when it is visible, otherwise from the surfels, otherwise from the GI volumes. The difference to the probe lighting is added on top, so the final gather only brings the near-field detail the probes miss, and replaces the quality 2 cone occlusion.
One ray per pixel is noisy, so it is filtered in two steps:
- Temporal: each pixel averages its own history (up to
x_gi_dfgi_lite_final_gather_historyframes), reprojected with motion vectors. - Spatial: 2–5 edge-aware à-trous passes that respect depth and normals.
This is built to be stable without TAA. Areas that keep losing their history, like moving leaves, fade towards the probe GI instead of flickering.
| Console variable | Default | Description |
|---|---|---|
x_gi_dfgi_lite_final_gather | 0 | Turns the final gather on. |
x_gi_dfgi_lite_final_gather_distance | 300 | Ray length in cm. About one probe spacing works well. |
x_gi_dfgi_lite_final_gather_rays | 1 | Rays per pixel (1–8). More rays lower noise at a linear cost. |
x_gi_dfgi_lite_final_gather_history | 32 | Frames averaged at most. Higher is smoother but reacts slower. |
x_gi_dfgi_lite_final_gather_filter_passes | 4 | À-trous passes (2–5). 4 passes cover 31×31 pixels. |
x_gi_dfgi_lite_final_gather_confidence_samples | 8 | Samples needed for full strength. Higher is calmer on foliage. |
x_gi_dfgi_lite_final_gather_screen_traces | 1 | Shade hits from last frame's screen when possible. |
x_gi_dfgi_lite_final_gather_max_ray_intensity | 10 | Brightest value a single ray may return. Stops sparkles from small bright sources. |
Settings
| Console variable | Default | Description |
|---|---|---|
x_gi_dfgi_lite_intensity | 1.0 | Overall indirect light intensity. |
x_gi_dfgi_lite_quality | 1 | See Quality. |
x_gi_dfgi_lite_probe_update_budget | 2048 | Probes retraced per frame across all live volumes, nearest first. Baked volumes never trace. |
x_gi_dfgi_lite_probe_realtime_budget | 16384 | Most probes traced per frame because visible pixels used them, on top of the update budget. 0 puts every probe on the rolling budget. |
x_gi_dfgi_lite_probe_realtime_interval | 1 | Minimum frames between traces of each visible probe, for every live volume. A Delayed volume's own interval applies when larger. |
x_gi_dfgi_lite_probe_realtime_hysteresis | 0.85 | History kept by visible probes on each update. DDGI's rules apply on top: large changes still come through within a frame or two, and sudden jumps are limited to a quarter per update. |
x_gi_dfgi_lite_surfel_drop_floating | 1 | Drops surfels left behind by moved objects: floating in front of the visible surface, or buried inside other geometry. Without it, a moved emitter keeps lighting its old place. |
x_gi_dfgi_lite_sky_fallback | 0.5 | Sky light strength outside every volume. 0 leaves those pixels without indirect light. |
x_gi_dfgi_lite_volume_view_distance | 50000 | Volumes further than this (cm) are ignored. |
x_gi_dfgi_lite_visibility_max_distance | 20000 | Distance (cm) where the quality 2 cone occlusion has faded out. |
x_gi_dfgi_lite_specular_min_roughness | 0.35 | Quality 3: roughness where probe specular starts. |
Runtime GI API
XFSDK Core, XFSDK Light, and the standalone XFSDK Hybrid SDF GI plugin expose the same runtime GI operations to Blueprint and C++.
The API selects between:
- No dynamic global illumination
- Unreal Engine Lumen Lite
- XFSDK Hybrid SDF GI
Blueprint functions
| Blueprint node | C++ function | Description |
|---|---|---|
| Enable Lumen Lite GI | XFSDK_EnableLumenLiteGI | Selects Unreal Engine Lumen and applies the Medium GI scalability level used by Lumen Lite. |
| Enable Hybrid SDF GI | XFSDK_EnableHybridSDFGI | Selects XFSDK Hybrid SDF GI. |
| Disable GI | XFSDK_DisableGI | Disables dynamic global illumination. |
| Get GI Mode | XFSDK_GetGIMode | Returns the currently selected GI mode. |
The three mode-selection functions return true when the complete configuration was applied. They return false when a required console variable is unavailable.
Failures are reported through the corresponding XFSDK diagnostics system as non-fatal errors.
GI modes
The shared logical modes are:
| Mode | Description |
|---|---|
Disabled | Dynamic global illumination is disabled. |
LumenLite | Unreal Engine Lumen is selected with sg.GlobalIlluminationQuality 1. |
HybridSDFGI | XFSDK Hybrid SDF GI is selected. |
Lumen Lite configuration changes global illumination only. The API does not modify reflection quality.
Product integration
The function names and behavior are shared across all three products. Module, class, and enum names differ where required by the standalone plugin.
| Product | Build.cs dependency | Header | API class | Mode enum |
|---|---|---|---|---|
| XFSDK Core | XFSDK_Runtime | XFSDK_GI_API.h | UXFSDKGIAPI | EXFSDKGIMode |
| XFSDK Light | XFSDK_System | XFSDK_GI_API.h | UXFSDKGIAPI | EXFSDKGIMode |
| Standalone Hybrid SDF GI | XFSDK_GI_Runtime | XFSDK_GI_Runtime_API.h | UXFSDK_GI_API | EXFSDK_GI_Mode |
XFSDK Core C++ usage
Add the runtime module to the consuming module:
PrivateDependencyModuleNames.AddRange(
new string[]
{
"XFSDK_Runtime"
});
Include the API:
#include "XFSDK_GI_API.h"
Select Hybrid SDF GI:
const bool bEnabled = UXFSDKGIAPI::XFSDK_EnableHybridSDFGI();
Select Lumen Lite:
const bool bEnabled = UXFSDKGIAPI::XFSDK_EnableLumenLiteGI();
Disable dynamic GI:
UXFSDKGIAPI::XFSDK_DisableGI();
Query the selected mode:
const EXFSDKGIMode Mode = UXFSDKGIAPI::XFSDK_GetGIMode();
XFSDK Light C++ usage
Add the system module to the consuming module:
PrivateDependencyModuleNames.AddRange(
new string[]
{
"XFSDK_System"
});
The header, class, enum, and functions are otherwise identical to XFSDK Core:
#include "XFSDK_GI_API.h"
UXFSDKGIAPI::XFSDK_EnableHybridSDFGI();
const EXFSDKGIMode Mode =
UXFSDKGIAPI::XFSDK_GetGIMode();
Standalone Hybrid SDF GI C++ usage
The standalone plugin exposes the shared functionality from its runtime module:
PrivateDependencyModuleNames.AddRange(
new string[]
{
"XFSDK_GI_Runtime"
});
Include the standalone API header:
#include "XFSDK_GI_Runtime_API.h"
Use the standalone API class:
UXFSDK_GI_API::XFSDK_EnableHybridSDFGI();
const EXFSDK_GI_Mode Mode =
UXFSDK_GI_API::XFSDK_GetGIMode();
Select Lumen Lite or disable GI:
UXFSDK_GI_API::XFSDK_EnableLumenLiteGI();
UXFSDK_GI_API::XFSDK_DisableGI();
Blueprint usage
The Blueprint nodes perform the same complete configuration as the C++ functions.
A typical graphics-settings flow is:
- Present Off, Lumen Lite, and Hybrid SDF GI to the player.
- Call the corresponding GI API node.
- Check the returned Boolean.
- Save the player's selected mode only when the call succeeds.
- Use Get GI Mode to initialize or refresh the settings UI.
Do not combine direct writes to the underlying GI method variables with the public API. Doing so may produce a configuration that no longer corresponds to one of the supported modes.
Debug views
x_gi_dfgi_lite_visualize | Shows |
|---|---|
1 | Distance-field occlusion (quality 2+). |
2 | Surfel coverage: yellow partial, green covered. Shows where probe rays find real materials. |
3 | GI volume probes. Magenta = inactive. |
4 | GI volume irradiance. |
5 | Volume weights: red = live, green = baked, blue = sky fallback. |
6 | Final gather correction: green adds light, red occludes. |
7 | Final gather history: red = rejected this frame, white = 16+ frames. |
Limitations
- Only geometry with mesh distance fields affects the GI. Very thin walls (below distance field resolution) can leak light; use thicker walls or denser volumes.
- Surfels are spawned from what is on screen. Probe rays that hit surfaces the camera has not seen yet use a neutral grey (30%) material until they are seen.
- Deferred shading only.
- Small emissive objects light the probes through their surfels, up to 1,024 emissive surfels per frame. Emitters must have been on screen to be picked up.
References
- Z. Majercik, J.-P. Guertin, D. Nowrouzezahrai, M. McGuire. Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields. JCGT, 2019. jcgt.org/published/0008/02/01
- Z. Majercik, A. Marrs, J. Spjut, M. McGuire. Scaling Probe-Based Real-Time Dynamic Global Illumination for Production. JCGT, 2021. jcgt.org/published/0010/02/01
- NVIDIA. RTXGI (DDGI) Unreal Engine plugin. github.com/NVIDIAGameWorks/RTXGI-DDGI
- D. Wright. Dynamic Occlusion with Signed Distance Fields. SIGGRAPH 2015, Advances in Real-Time Rendering.
- H. Halén, A. Brinck, K. Hayward, X. Bei. Global Illumination Based on Surfels. SIGGRAPH 2021, Advances in Real-Time Rendering (EA SEED).
- R. Wang. SurfelPlus. github.com/WANG-Ruipeng/SurfelPlus
- T. Roughton, P.-P. Sloan, A. Silvennoinen, M. Iwanicki, P. Shirley. ZH3: Quadratic Zonal Harmonics. Activision, I3D 2024.
- P.-P. Sloan. Deringing Spherical Harmonics. SIGGRAPH Asia 2017 Technical Briefs.
- T. Sousa. Fast as Hell: idTech 8 Global Illumination. SIGGRAPH 2025, Advances in Real-Time Rendering in Games (DOOM: The Dark Ages).
- H. Dammertz, D. Sewtz, J. Hanika, H. Lensch. Edge-Avoiding À-Trous Wavelet Transform for Fast Global Illumination Filtering. HPG 2010.
- C. Schied et al. Spatiotemporal Variance-Guided Filtering. HPG 2017.
- D. Wright, K. Narkowicz, P. Kelly. Lumen: Real-time Global Illumination in Unreal Engine 5. SIGGRAPH 2022, Advances in Real-Time Rendering.
- Activision. VRRT. SIGGRAPH 2026 (re-cast rays reuse their random numbers, slide 58).