Pause a game frame and step forward one frame. Almost nothing has changed: the camera nudged a
pixel, a character's arm swung a few degrees, a shadow crept. Ninety-something percent of the
picture is identical to the frame you just drew. Redrawing all of it from scratch, sixty
times a second, is heroic — and mostly wasted. This is the central fact renderers now build their
whole strategy around: consecutive frames are nearly the same. We call it
temporal coherence, and exploiting it is what makes modern real-time
The plan of this page: first, why coherence lets us amortise expensive work across many frames instead of paying for it every frame; then temporal anti-aliasing (TAA), which accumulates samples over time by reprojecting old frames; then denoising, which turns a splotchy one-sample path trace into a clean image using geometry buffers as a guide; and finally the artefacts all of this fights — ghosting and flicker — and how history gets rejected when it goes stale.
Every technique below is a variation on the same recipe: reproject (find the old position), reuse (blend the history in), and reject (throw the history away when it can't be trusted). Get those three right and one cheap sample per frame, blended over time, behaves like dozens of expensive ones.
A motion vector stored at pixel
The engine already knows this: it has the current and previous
A single sample at a pixel's centre gives jagged edges: it either hits the triangle or misses, with nothing in between. Classic supersampling fixes this by taking many sub-pixel samples per frame — expensive. TAA spreads those samples across time instead. Each frame the camera is jittered by a sub-pixel offset (a low-discrepancy sequence like Halton picks the offsets so that over, say, eight frames they tile the pixel evenly). Frame by frame the renderer samples a slightly different spot inside every pixel.
Those samples are combined by reprojecting the accumulated history colour
from last frame — follow the motion vector to
With
The catch is the same one that haunts everything here: the reprojected history is only valid if that pixel really was showing the same surface last frame. When it wasn't, TAA smears — which brings us to the artefacts, but first, denoising, which pushes the very same idea much harder.
Here is the one geometric idea the whole page rests on. The lower strip is the previous frame; the
upper strip is the current frame. A surface point sits at pixel
Everything now depends on the arrow being right. If the motion vector points somewhere the surface was not — because it was hidden, or off screen, or the motion was mis-estimated — the history we fetch belongs to a different surface, and we get a smear.
Path tracing shoots random rays to estimate the light arriving at each pixel. With a full budget of
thousands of samples the estimate converges to a clean image; with the one sample per
pixel a real-time renderer can afford, the estimate is extremely noisy — a blizzard of
bright and dark speckles, because the
The trick that makes it work: the renderer is cheap to produce auxiliary geometry buffers that are not noisy at all —
A good denoiser blurs the noisy lighting heavily, but only across pixels the guide buffers say belong to the same surface — similar normal, similar depth. It refuses to blur across a depth cliff or a normal discontinuity, so edges stay crisp while flat regions are smoothed. This is the idea behind the edge-avoiding À-Trous filter and its temporal cousin SVGF (Spatiotemporal Variance-Guided Filtering), which additionally accumulates samples over time by exactly the TAA reprojection above — a spatial blur guided by the geometry, plus a temporal accumulation guided by motion vectors.
The modern alternative is a machine-learned denoiser — NVIDIA's OptiX denoiser or Intel's Open Image Denoise (OIDN) — a neural network trained on pairs of noisy and clean renders that learns to map (noisy colour + albedo + normal) to the converged image. It often beats hand-written filters on detail, at the cost of a trained model and inference time.
None of the three parts is sufficient alone: one sample is far too noisy, temporal accumulation alone still leaves residual noise and lags on motion, and a spatial denoiser alone over-blurs. Together they turn a noisy trickle of rays into a stable, clean, animated image — the pipeline behind real-time path-traced games and the "ray reconstruction" style upscalers.
It seems perverse to deliberately shake the camera by a fraction of a pixel every frame. But a
fixed sample at each pixel centre can only ever tell you what is at the centre — it is blind
to a triangle edge slicing through the pixel. By moving the sample point around inside the pixel over
successive frames, the accumulated average sees the whole pixel's worth of coverage, and the edge
resolves smoothly. The offsets aren't random: a low-discrepancy sequence (Halton, or a Poisson-disc
set) is chosen so that after
A pixel at screen position
Step 1 — reproject. The previous screen position is
Step 2 — validate. Compare the history's stored depth and normal at
Step 3 — blend (history valid). With
Step 3′ — reject (history invalid). Suppose the depth at
Reprojected history is wrong wherever a surface was hidden last frame or the motion vector is off. Two classic failures:
The fix is history rejection: at every pixel, sanity-check the reprojected history against the current geometry — depth mismatch, normal mismatch, or a colour far outside the local neighbourhood's range (neighbourhood colour clamping) — and when it fails, throw the history out and fall back to the current sample. You trade a flash of extra noise on those pixels for correctness. Too little rejection gives ghosting; too much gives flicker and lost detail — tuning that balance is most of the art of a good temporal filter.
A tiny
Monte Carlo error shrinks like
The