Graphics epic: global illumination (SSAO, local reflections, indirect diffuse)
Goal
Add a global-illumination solution so indirect light — bounce lighting, contact/ambient occlusion, local reflections — is computed from the scene itself rather than approximated by a single distant environment probe.
Today the only indirect term is the IBL ambient added in subsystems/render/shaders/scene.frag.glsl:
vec3 irradiance = evalSH(N, ubo.env_sh) * intensity; // distant env, 9 SH coefficients
vec3 diffuse_ibl = irradiance * albedo / PI * (1.0 - metallic);
vec3 prefiltered = textureLod(env_prefiltered, R, roughness * max_lod).rgb * intensity;That is a distant environment only. It has no notion of the scene occluding itself, so:
- No occlusion. Every crevice, every surface under an awning or table, receives the
full hemisphere of sky irradiance. Comparing the Bistro sample against the
ORCA reference render,
this is the single largest perceptual difference — the reference is defined by its
contact darkening.
occlusion_mapcannot rescue this: the Bistro*_Specularmaps have an identically-zero red (occlusion) channel across all 633 textures, so there is no baked AO in the dataset to bind. - No bounce. Light does not carry colour between surfaces: no red spill from the awnings onto the stucco, no green bounce from the storefront onto the pavement.
- No local reflection.
env_prefilteredis the distant HDRI, so every reflective surface mirrors the sky regardless of what is actually in front of it. This is why the Bistro storefront glass shows a blurred HDRI skyline instead of the street and interior (see #156). - Shadowed surfaces get no indirect light of their own — only the directional light is
shadowed (
shadowFactor, primary directional, 3x3 PCF); ambient is unshadowed and flat.
Scope
This is deliberately an umbrella issue: "GI" is several separable techniques, and they do not have to land together. Rough ordering by cost/benefit for a raster engine:
- Screen-space ambient occlusion (GTAO or a modern SSAO) applied to the ambient term. Cheapest, biggest visual delta, no authoring or bake step, no new asset formats.
- Screen-space reflections for the specular term, falling back to
env_prefilteredon ray miss. Fixes mirrored-sky glass and wet cobblestones. - Reflection probes — baked local cubemaps with parallax correction, replacing the
single global
env_prefilteredper-object. Gives correct interior reflections where SSR has no on-screen information. - Diffuse GI proper. Options, in rough order of implementation cost:
- Baked irradiance volumes / light probes (offline bake, cheap at runtime, static only)
- Lightmaps (highest quality for static geometry, needs UV unwrapping + a bake pipeline)
- DDGI-style dynamic probes (dynamic, needs ray tracing or a voxel/SDF proxy)
- Voxel cone tracing (fully dynamic, expensive, aliasing-prone)
Each of 1–4 should become its own issue with its own design once this is scheduled; this issue tracks the overall direction and the decision of which diffuse-GI approach to commit to.
Decisions to make
- Static vs. dynamic. A bake-based approach (lightmaps / irradiance volumes) is far cheaper at runtime and fits the current renderer, but needs a bake pipeline in the editor, a new baked-data asset type, and it forecloses runtime-modified geometry.
- Ray tracing availability. SDL3 GPU exposes no ray-tracing API today, which rules out hardware-RT approaches (DDGI, RTXGI) for now and pushes toward screen-space + baked techniques.
- Where it lives. SSAO/SSR are post-process passes and belong with the existing HDR
pipeline (
subsystems/render/postprocess_pipeline.zig, #136 (closed)). Probes/lightmaps need editor-side bake tooling and new asset types, closer to #16 (closed) (Asset Database).
Prerequisites
- SSAO and SSR both need a depth + normal prepass (or a G-buffer). The renderer is currently forward-only with an HDR colour target; some form of depth/normal buffer is a shared prerequisite for both, and is the natural first piece of work.
Related
- #132 Bistro sample — the driving use case and the visual benchmark
- #144 (closed) Prefiltered cubemap IBL — the distant-environment specular this would extend
- #136 (closed) HDR post-processing pipeline — where screen-space passes would slot in
- ADR-0010 Lighting and shadows