GI: alpha-blended windows flash brighter rapidly (GI off fixes it) #1438

Closed
opened 2026-11-04 08:29:32 +00:00 by sky_line · 1 comment
Owner

Owner report (2026-11-04, RTX 5090, current main-based test builds): with GI on (RenderVKGI), alpha-blended windows flash brighter rapidly. Turning GI off fixes it.

Context:

  • Alpha-blended surfaces are lit by the forward alpha pass, whose GI comes from the coarse radiance cache (not the denoised per-pixel GI the deferred path uses) -- see #1419 / PR #1420 (near-opaque texels >= 0.99 now go to the G-buffer; translucent glass stays forward).
  • Related history: #1171 (GI on glass showed the radiance cache cell grid), #1406 (GI objects flash dark intermittently; fixes ccfcbd4946, 95bda5a257 bound emitter change spheres and kept denoiser history inside them), #1138 (ReSTIR emissive pulses).

To find: which GI term the forward alpha shader reads (radiance cache lookup, probe/GI blend, hit-light / change tags), why it changes frame to frame for a static window (cache cell churn or eviction, change-tag resets, temporal reuse not applied to cache reads, alternating cache slots, light-change cuts, async GI lag mismatch with the frame that reads it), and fix it so translucent surfaces get temporally stable GI with no flashing, at no extra per-frame cost for scenes without blended surfaces.

Owner report (2026-11-04, RTX 5090, current main-based test builds): with GI on (RenderVKGI), alpha-blended windows flash brighter rapidly. Turning GI off fixes it. Context: - Alpha-blended surfaces are lit by the forward alpha pass, whose GI comes from the coarse radiance cache (not the denoised per-pixel GI the deferred path uses) -- see #1419 / PR #1420 (near-opaque texels >= 0.99 now go to the G-buffer; translucent glass stays forward). - Related history: #1171 (GI on glass showed the radiance cache cell grid), #1406 (GI objects flash dark intermittently; fixes ccfcbd4946, 95bda5a257 bound emitter change spheres and kept denoiser history inside them), #1138 (ReSTIR emissive pulses). To find: which GI term the forward alpha shader reads (radiance cache lookup, probe/GI blend, hit-light / change tags), why it changes frame to frame for a static window (cache cell churn or eviction, change-tag resets, temporal reuse not applied to cache reads, alternating cache slots, light-change cuts, async GI lag mismatch with the frame that reads it), and fix it so translucent surfaces get temporally stable GI with no flashing, at no extra per-frame cost for scenes without blended surfaces.
sky_line added this to the Slipstream project 2026-11-04 08:29:35 +00:00
Collaborator

Checked in world on a build that includes cfff6e83e8: the window no longer flashes. Closing as fixed by that commit.

What's left: a faint pulse. Only on glass in the shadow of a tree outside, and barely noticeable. The GI log at the time:

GI delta totals: ... store_reset=0 agent_shift=0 dropped_frame=0 cache_restart_headers=0; local_spheres=64; headers_with_spheres=251/251

So every frame has change spheres, all 64 slots are in use (new ones merge into larger spheres), and there are no cache restarts. Glass cells inside a sphere only keep the 4-frame mean, and glass is fed by sparse samples, so a little noise remains. It reaches the glass 1:1 through giForwardRefl's lum(E)/lum(probe) scale (clean_surface_light.glsl ~212-219).

Refinements from reading the code, if this ever needs more:

  • Weight the cell mean by samples per frame. The resolve in clean_deferred_light.comp (~4962) gives a 1-sample frame the same weight as a 200-sample frame. Keep a sample-weight total in the reserved word gi_data[3cap+s].z, use alpha = acc.w / (Nw + acc.w), and cap Nw at a 4-frame equivalent inside spheres instead of cutting the window.
  • Restart less eagerly. Inside a sphere, restart a cell only after a much longer unsampled gap (e.g. 32 reference frames rather than 4). Off-screen cells still restart.
  • Fade cells in on glass. In giCacheForward, weight each corner by min(Nw / Nmin, 1), so a young cell blends in against the probes instead of switching from 0 to 1.
  • Small separate bug: duplicate cells. giCacheFindOrInsert (clean_gi_common.glsl ~333) takes the first freed slot before checking the rest of the chain for the key. That can create a second cell with the same key, which costs one empty frame per occurrence.

A/B levers if it gets reported again:

  • RenderVKGIDebug 6 (magenta = cell in a sphere).
  • RenderVKGISpecOcclusion 0.
  • RenderVKGICacheFrames 32 → 128.
  • RenderVKGIFireflyClamp 4 → 1.
  • A smaller RenderVKGIRayLength, which shrinks the sphere padding.
Checked in world on a build that includes cfff6e83e8: the window no longer flashes. Closing as fixed by that commit. **What's left: a faint pulse.** Only on glass in the shadow of a tree outside, and barely noticeable. The GI log at the time: ``` GI delta totals: ... store_reset=0 agent_shift=0 dropped_frame=0 cache_restart_headers=0; local_spheres=64; headers_with_spheres=251/251 ``` So every frame has change spheres, all 64 slots are in use (new ones merge into larger spheres), and there are no cache restarts. Glass cells inside a sphere only keep the 4-frame mean, and glass is fed by sparse samples, so a little noise remains. It reaches the glass 1:1 through `giForwardRefl`'s `lum(E)/lum(probe)` scale (`clean_surface_light.glsl` ~212-219). **Refinements from reading the code, if this ever needs more:** - **Weight the cell mean by samples per frame.** The resolve in `clean_deferred_light.comp` (~4962) gives a 1-sample frame the same weight as a 200-sample frame. Keep a sample-weight total in the reserved word `gi_data[3cap+s].z`, use `alpha = acc.w / (Nw + acc.w)`, and cap `Nw` at a 4-frame equivalent inside spheres instead of cutting the window. - **Restart less eagerly.** Inside a sphere, restart a cell only after a much longer unsampled gap (e.g. 32 reference frames rather than 4). Off-screen cells still restart. - **Fade cells in on glass.** In `giCacheForward`, weight each corner by `min(Nw / Nmin, 1)`, so a young cell blends in against the probes instead of switching from 0 to 1. - **Small separate bug: duplicate cells.** `giCacheFindOrInsert` (`clean_gi_common.glsl` ~333) takes the first freed slot before checking the rest of the chain for the key. That can create a second cell with the same key, which costs one empty frame per occurrence. **A/B levers if it gets reported again:** - `RenderVKGIDebug 6` (magenta = cell in a sphere). - `RenderVKGISpecOcclusion 0`. - `RenderVKGICacheFrames` 32 → 128. - `RenderVKGIFireflyClamp` 4 → 1. - A smaller `RenderVKGIRayLength`, which shrinks the sphere padding.
TheSlowly removed their assignment 2026-11-06 06:41:17 +00:00
TheSlowly 2026-11-06 06:41:17 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sky_line/Slipstream#1438
No description provided.