About Store Forum Documentation Contact



Post Reply 
Global Illumination (GI)
Author Message
Fex Offline
Gold Supporter

Post: #1
Global Illumination (GI)
It's a subtle lighting feature, but in dark scenes it can make a difference.
Intensity of GI must be increased to really see it especially if there is an ambient light source.
RT hardware accelerated GI has much better performance than pure software (rasterized) GI.

GI ON, intensity cranked so effect is obvious:
[Image: Screenshot-From-2026-07-08-08-19-29.png]


GI OFF:
[Image: Screenshot-From-2026-07-08-08-19-36.png]


GI ON , yellow arrow is sun direction:
[Image: Screenshot-From-2026-07-08-08-20-39.png]

GI OFF:
[Image: Screenshot-From-2026-07-08-08-20-51.png]

Left Side GI ON / Right Side GI OFF split screen:
[Image: Screenshot-From-2026-07-08-08-38-31.png]

AI Generated Summary:

Fully Dynamic Global Illumination for Esenthel — No Baking, No Authoring

I added a complete real-time diffuse Global Illumination system to the engine’s deferred renderer.

The headline: zero authoring — no baked lightmaps, no hand-placed probes, and no precompute step.

You flip one switch and neutral surfaces start picking up colored bounce light from the walls, terrain, and objects around them. Time-of-day is fully dynamic. The system is Vulkan-only because it needs the compute path, and it is off by default. Existing scenes render byte-for-byte identically until an app explicitly opts in.

There are two interchangeable producers that fill the lighting probes:
  • []Rasterized cube capture — works on any GPU and is always available as the fallback.
    []Hardware ray-traced capture — optional ray-query path for GPUs that support it.

How it works
  • DDGI-style probe grid

    A camera-centered 3D grid of irradiance probes follows the camera. The deferred light pass swaps the old flat ambient term for trilinearly interpolated probe irradiance.
  • Toroidal scrolling

    As the camera moves, the probe volume scrolls toroidally, addressed by integer cell index, instead of re-capturing everything. This prevents a re-capture storm when moving through the world.

    This also makes it floating-origin and large-world safe because the GI volume effectively rebases for free.
  • Cascades

    Range comes from nested cascades at geometrically increasing spacing. Three cascades cover roughly 24 m to 216 m, with a cross-cascade seam blend so there is no hard visible ring at the cascade boundaries.
  • DDGI-standard atlases

    Each probe captures visibility, either rasterized into a small cube or ray-traced, then compute integrates the result into octahedral irradiance and Chebyshev depth-moment atlases.

    The depth moments suppress light leaking through thin walls, and a surface-normal bias helps as well.
  • Decoupled capture vs. relight

    Geometry capture and lighting relight are separated. Both are hard-capped per frame.

    The expensive geometry capture is time-sliced and budgeted, so the cost stays bounded. A static scene captures nothing, so it is free when you are not moving. Irradiance converges through temporal blending.
  • Free time-of-day relight

    An optional producer bakes a lighting-independent cube once and relights it each frame with per-bounce sun shadowing. Moving the sun costs no re-capture.
  • Analytic re-seeding

    Scrolled-in probe slots are analytically re-seeded, which kills stale-bounce ghosting during fast movement.
  • Half-resolution evaluation

    Half-res evaluation plus depth-aware bilateral upscale keeps the light-pass cost down.
  • Optional SSGI

    A screen-space near-field bounce layer can be enabled on top of the probe GI for close-range contact GI.

Hardware ray-traced path — opt-in, additive

When ray-query hardware is present and a scene acceleration structure is registered, probe capture can be ray-traced instead of rasterized. This gives correct per-direction occlusion and bounce with no cube-face seams.
  • RT occlusion moments

    GI.raytrace replaces the depth-cube producer with ray-traced occlusion moments. The light pass is unchanged.
  • RT bounce radiance

    GI.raytrace_radiance traces the diffuse bounce itself using cosine-weighted hemisphere gathering with Fibonacci-spiral rays.

    It supports textured and average-color albedo. Terrain with no UVs samples the texture’s mean color. It uses the correct hit-surface normal, NdotL, sun shadow rays, radiosity-style multi-bounce, and a per-frame sky-only cube so miss rays sample the real rendered sky.

    It reaches pixel parity with the rasterized producer at the same intensity on both Cornell and world scenes.
  • Zero-registration mode

    GIRayTrace.auto_scene = true lets the renderer feed every opaque mesh it draws into the acceleration structure automatically.

    Streamed world areas enter the TLAS as they draw and drop out as they stream away, with no app code required. Rebuilds are recorded into the frame command buffer, so there is no GPU stall.

The system is fully hardware-gated and TLAS-gated. If RT is off, unsupported, or unregistered, it falls back to rasterized capture. The software DDGI path is untouched.

Verified working on both AMD RADV and NVIDIA.

Demos

Vulkan build, under Tutorials/Source/14 - Game Basics/

Tutorial_14_DynamicGI
The basics: a neutral scene picking up colored bounce light, with live time-of-day. This is the color-bleed proof.

Tutorial_14_WorldGI
GI over a real streamed Game::World with terrain and props, plus point-light and time controls.

Tutorial_14_LargeWorldGI
GI running under the large-world floating origin. This proves it survives rebases without re-warming.

Tutorial_14_GIShowcase
The “all the knobs” demo. A Cornell room with split-screen A/B.

Controls include:
  • []V — split-screen A/B
    []- / = — intensity
    []1 / 2 / 3 — cascade count
    []R — relight
    []B — Chebyshev
    []A — TAA
    []N — SSGI
    []Y — RT moments
    []U — RT radiance
    []Sun, light, and wall toggles

Tutorial_14_RTWorldGI
The payoff: ray-traced GI over a playable streamed world via the zero-registration auto-scene hook.

Controls include:
  • []WASD — move
    []G — GI on/off, showing near-black ambient vs. bounced sunlight
    []U — RT radiance vs. rasterized capture
    []Y — RT moments
    []T — time-of-day
    []- / = — intensity

How it is turned off and on

Everything defaults off at the engine level. These are the relevant defaults on the global GI object in Engine/H/Graphics/GI.h, plus GIRayTrace:

GI.enabled
Default: false
Turns on the whole system. Off means legacy flat ambient.

GIRayTrace.auto_scene
Default: false
Turns on zero-registration RT scene feeding.

GI.raytrace
Default: false
Turns on ray-traced occlusion moments.

GI.raytrace_radiance
Default: false
Turns on ray-traced bounce radiance.

GI.relight
Default: false
Turns on the free-time-of-day relight producer.

GI.ssgi
Default: false
Turns on screen-space near-field bounce.

GI.capture_shadows
Default: false
Turns on sun-shadowed lit-cube capture.

GI.chebyshev
Default: true
Turns on leak suppression when GI is enabled.

GI.half_res
Default: true
Turns on half-res evaluation and upscale.

GI.auto_light
Default: true
Derives sun and sky lighting from the live scene.

Canonical app opt-in path

An app opts in from InitPre or Init:

GI.enabled = true;
GI.intensity = 2.0f;
GIRayTrace.auto_scene = true;
GI.raytrace_radiance = true;

GI.enabled is the master switch. Nothing renders GI without it.

GI.intensity controls the indirect multiplier, where 1 is physical.

GIRayTrace.auto_scene is optional and lets the renderer register the scene for ray tracing automatically.

GI.raytrace_radiance is optional and enables ray-traced bounce radiance. It falls back if unsupported.

There are also EE_GI environment-variable overrides, such as:

EE_GI=1
EE_GI_RAYTRACE_RADIANCE=1
EE_GI_INTENSITY=...

Those exist mainly for headless A/B testing. They are not the intended shipping path.

Beyond the app switch, GI is gated on backend support. GI.active() requires the Vulkan compute path. The RT path is additionally gated on ray-query hardware.

So on a non-Vulkan backend, or a GPU without ray-query support, the relevant paths simply no-op or fall back.

Net result: if you do not opt in, nothing about your scene changes.

Build and run one demo

cmake --build cmake-build-release-vulkan --target Tutorial_14_GIShowcase -j $(nproc)

EE_NO_MSG_BOX=1 ./Tutorials/Tutorial_14_GIShowcase

Documentation

Full design notes and knob reference are in:
  • []The README’s Dynamic Global Illumination section
    []docs/gi-raytracing-design.md

Available in this engine fork:
https://github.com/DrewGilpin/EsenthelEngine
Today 01:44 PM
Find all posts by this user Quote this message in a reply
Post Reply