Denoising very noisy screen-space input (SSGI especially) cannot be solved by stacking a separate temporal denoiser in front of the upscaler. Verified 2026-07-10 against three r185's recurrentDenoise / temporalReproject in examples/10-ssgi-denoise (kept as experimental documentation, not a library feature):
Any second temporal resolver reprojects by velocity, which is jitter-free by contract. It therefore cannot see our sub-pixel jitter, so it (a) rejects the misaligned history and the noise survives, and (b) cancels the very jitter variance the upscaler needs, so aliasing returns. Spatial-only denoise + upscaler-owns-temporal sidesteps the conflict but inherits the third-party à-trous kernel's halos, step-lines, and update-cadence skipping.
The real fix is to fuse GI history into our accumulation: reprojected with our motion vectors, sampled at our jitter, with GI-appropriate variance handling rather than the AA-tuned clip. MomentsPass already provides the per-pixel (E[x], E[x²]) statistics an SVGF-class variance estimate needs, over any float texture, with no beauty/exposure assumption baked in — so half the machinery exists.
This is genuine R&D touching the core accumulate pass, not an incremental add. Two things make it tractable now that didn't hold when it was first deferred: the guides bundle means a consumer's temporal front-end and ours are already the same computation, and an external SSGI/SVGF consumer exists to co-validate against.
Prerequisite: the accumulate pass's still-scene behavior is newly settled (#1) — build on that, don't re-litigate it. Any variance handling added here must preserve the two convergence rules recorded in CLAUDE.md (never age by clip magnitude; don't let per-phase boxes re-snap converged history).
Denoising very noisy screen-space input (SSGI especially) cannot be solved by stacking a separate temporal denoiser in front of the upscaler. Verified 2026-07-10 against three r185's
recurrentDenoise/temporalReprojectinexamples/10-ssgi-denoise(kept as experimental documentation, not a library feature):Any second temporal resolver reprojects by velocity, which is jitter-free by contract. It therefore cannot see our sub-pixel jitter, so it (a) rejects the misaligned history and the noise survives, and (b) cancels the very jitter variance the upscaler needs, so aliasing returns. Spatial-only denoise + upscaler-owns-temporal sidesteps the conflict but inherits the third-party à-trous kernel's halos, step-lines, and update-cadence skipping.
The real fix is to fuse GI history into our accumulation: reprojected with our motion vectors, sampled at our jitter, with GI-appropriate variance handling rather than the AA-tuned clip.
MomentsPassalready provides the per-pixel(E[x], E[x²])statistics an SVGF-class variance estimate needs, over any float texture, with no beauty/exposure assumption baked in — so half the machinery exists.This is genuine R&D touching the core accumulate pass, not an incremental add. Two things make it tractable now that didn't hold when it was first deferred: the guides bundle means a consumer's temporal front-end and ours are already the same computation, and an external SSGI/SVGF consumer exists to co-validate against.
Prerequisite: the accumulate pass's still-scene behavior is newly settled (#1) — build on that, don't re-litigate it. Any variance handling added here must preserve the two convergence rules recorded in
CLAUDE.md(never age by clip magnitude; don't let per-phase boxes re-snap converged history).