FidelityFX Denoiser (AMD, SDK v1.1.4) ported to WGSL
One ray per pixel in, a stable image out. Everything below runs live on your GPU in WebGPU.
What you are looking at
The three panels show the same frame of the same scene (spheres and boxes on a plane). The camera drifts slowly along a path and then jump-cuts to a different view; use Pause camera / Camera cut to take your time. Switch between the shadows and reflections signal with the links above.
- noisy 1 spp: the raw input. Each frame every pixel traces one random ray, so the image is grainy and flickers.
- denoised: the FidelityFX shadow or reflection denoiser (ported to WGSL) turns that into a clean, stable image.
- reference: the same frame with many rays averaged per pixel. This is what a perfect denoiser would produce; the closer the middle panel is to it, the better.
Where the signal comes from
The shadows and reflections are generated by this demo's own analytic WGSL ray tracer. In shadows mode each pixel traces one random ray toward a point on an area light and records whether it is visible (0 or 1); averaged over many rays this gives soft penumbrae. In reflections mode each pixel traces one GGX-sampled glossy reflection ray. The denoiser only ever sees that 1-sample signal plus the G-buffer guides (depth, normals, motion vectors, roughness); it never sees the reference.
Why it matters
Real-time ray-traced and stochastic effects, in games and in three.js scenes, can only afford about one ray per pixel per frame. A temporal denoiser reuses past frames (via motion vectors) and neighbouring pixels to turn that into a stable image: on an Apple M5 Pro at 1080p it takes about 0.5 ms for shadows and 1.7 ms for reflections.
Honest caveats
- Reflections run slightly dark compared with the reference because FidelityFX suppresses fireflies (bright outlier samples).
- Quality dips briefly after a camera cut: the history is reset and has to rebuild over a few frames, so the middle panel is grainier right after each cut.