Path Tracer — WebAssembly

A C++ physically-based path tracer compiled to WASM with Emscripten, running entirely client-side. Binned-SAH BVH, iterative path integration with Russian roulette, emissive materials, spheres and quads. The image refines sample-by-sample in real time — nothing is pre-rendered, and no work leaves your machine. Pick White furnace test to watch the renderer prove its own energy conservation.

Loading WASM module…
0 / 0 spp
ms / pass
samples / sec
elapsed
primitives
BVH nodes
BVH depth

Materials in the sphere field
Algorithms

Turn BVH acceleration off and watch the ms / pass figure — that is the acceleration structure earning its keep, measured live. Both settings render the bit-for-bit identical image; the test harness asserts that with ==.

Honest limitations (measured, not hand-waved)
  • No next-event estimation. This is a naive path tracer: it never samples light sources directly, so a path only finds a light by randomly bouncing into it. That is nearly free when the "light" is the whole sky, and expensive when it is a small ceiling quad. Measured with the verification harness (per-pixel standard deviation across independent renders at 64 spp, normalised by each scene's mean radiance): the Cornell box is ~22× noisier per sample than the sky-lit sphere field. Because Monte Carlo error falls as 1/√N, matching its quality costs ~490× the samples. That is why the Cornell box looks grainy here and the sphere field does not.
  • Single-threaded. No pthreads or SharedArrayBuffer, a deliberate trade so the demo hosts as plain static files with no COOP/COEP headers.
  • No importance sampling of BRDFs beyond the cosine lobe, no textures, no participating media, no spectral rendering, no denoiser.
  • Numerically-tangent sphere hits are rejected by design. At exact tangency the front-face/back-face sign is float noise; a misclassified grazing ray gets an inward normal and is trapped inside the sphere. The trim is 5×10⁻⁹ of a radius.