I wanted to actually understand ray tracing — not just the vocabulary — so I built a path tracer from first principles: rays, intersection math, Monte Carlo sampling, physically based materials, and a spatial acceleration structure, all measured and benchmarked rather than taken on faith.
| Area | Where it shows up here | Status |
|---|---|---|
| Light transport & physically based materials | Ray–sphere intersection, recursive path tracing, Lambertian / metal / dielectric BRDFs, indirect light from pure ray bounces | demonstrated |
| Data structures & performance | Bounding volume hierarchy, multithreaded render loop, zero warnings under -Wall -Wextra | demonstrated |
| Profiling & benchmarking | Built-in --benchmark mode measuring BVH vs. linear-scan intersection cost | demonstrated |
| GPU acceleration | Not yet — next step is a HIP / ROCm port of this same ray gen → intersect → shade loop, running natively on an RX 9060 XT (RDNA4) | next up |
| Resampled direct lighting (ReSTIR) | Resampled importance sampling (weighted reservoir sampling, Bitterli et al. 2020) for direct lighting, plus spatial reuse of neighboring pixels' reservoirs — measured up to 1.96× lower MSE than uniform-pick NEE at equal sample counts. | demonstrated |
| Neural rendering | Not yet — plan to train a small NeRF / Gaussian Splatting reproduction on views rendered by this tracer | next up |
Without an acceleration structure, testing a ray against a scene costs O(N) — every object, every ray. A bounding volume hierarchy lets a ray that misses a bounding box skip everything inside it, which is the same underlying idea GPU ray-tracing hardware accelerates in silicon. I measured it directly on this scene's 487 spheres:
Direct lighting means picking a light and testing whether it's visible — but a scene with dozens of small lights makes blind uniform picking noisy, since most picks land on a light that barely matters from a given shading point. Resampled importance sampling (RIS) scores several candidate lights per hit and streams them through a weighted reservoir (Bitterli et al., ReSTIR 2020) so the one candidate that pays for a shadow ray is whichever actually looked promising — same one-shadow-ray-per-hit cost as before, just aimed better. Spatial reuse then lets a pixel fold in its already-built neighbors' reservoirs as free extra candidates, rejecting any neighbor across a normal or depth discontinuity so reuse can't leak across a silhouette. I measured both against a uniform-pick baseline with an MSE sweep across light counts and sample budgets (benchmarks/mse_sweep.py):
Port ray gen → intersect → shade into raw HIP kernels on an RX 9060 XT, hand-writing the BVH traversal first so the algorithm is mine rather than the API's, then profile it on a real GPU timeline.
Once the HIP port runs, bring in HIPRT — AMD's open-source ray tracing SDK — as a second traversal mode, and measure what hardware-accelerated BVH traversal actually buys over the kernels I wrote myself.
Generate the multi-view training data with this same path tracer — the renderer generating the training data the model learns from.