Task 5 of 5
You have watched the noise go. Now measure it, because the rate it goes at is the
single most important number in rendering — and it is the same 1/√n that
Monte Carlo Methods derives for a dart-throwing estimate of π. A path tracer is
that estimator with a much more interesting integrand.
Measuring it needs a reference, and the honest trick is to build one out of thin air: run the accumulation twice, with two different slices of the random stream. Neither run is the truth, but their errors are independent, so the RMS gap between them is √2 times either one's own error. Halve the square and you have measured your own noise with no ground truth anywhere in sight.
Plot that against errs[0] / √n on a log axis. If the two curves lie on top
of each other, the estimator is behaving exactly as theory says — and the shape of them is
the bad news in the theory: halving the noise costs four times the samples. That
single fact is why production renderers spend their effort on importance sampling and
denoisers instead of simply waiting longer.
sqDiff — half the squared difference between
the two runs at this pixel — and build the 1/√n reference curve to plot
against it.sqDiff, return 0.5 * d * d for d = a - b at this pixelerrs[0] / Math.sqrt(f + 1) into ideal each passplot on a log axis (already wired)Run A is off by eₐ and run B by e_b, independently.
The gap between them has variance var(eₐ) + var(e_b) = twice one run's.
So the square of the gap, halved, estimates the square of one run's error — and the
square root of the mean of that is the RMS error you want.
const d = a[this.thread.y][this.thread.x] - b[this.thread.y][this.thread.x];
return 0.5 * d * d;
Squaring in the kernel and square-rooting once in JavaScript is the usual split: the per-pixel work is parallel, the final scalar is not.
Anchor it to the measurement you already have, so the two lines start together and any drift between them is real:
ideal.push(errs[0] / Math.sqrt(f + 1));1/√n because the exponent itself cannot be moved; low-discrepancy
(quasi-Monte Carlo) sequences buy a slightly better exponent on smooth integrands; and
OptiX's and OIDN's neural denoisers give up unbiasedness altogether to get the picture
twenty times sooner. The measurement you just made — two independent runs, no reference
image — is also how those denoisers are evaluated in practice.
This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.