Photon Mapping With Some Twists

by Eric Johnson

Imlemented in Rust

“a systems programming language that runs blazingly fast, prevents nearly all segfaults, and guarantees thread safety”


My Oppinion

What I liked

What I didn't like

Photon Mapping

What I did differently

Per-Object Photon-Maps

The classic implementation of photon maps has a global photon map for the entire scene. At the point when the photon map is being sampled though, the ray tracer has already done a lot of the work by finding out which object it hit. By storing separate separate photon maps for each object, I hoped to leverage the raytracing and reduce the time needed to search for nearby photons.

I see some additional benefits to storing the photons this way. First is that we can now use a 2d data structure mapped to surface of an object instead of using a bigger 3d data structure. Another benefit is that it solves the problem of photons on the surface of other objects contributing to the radius of an object in corners.

Sphere Surface Partitioning

The original developers of photon mapping advocate the use of a KD-tree to store the photons. This recomendation makes sense for a global photon map, but since I now store a photon map per object, we can narrow down the search space to the surface of an object, and a KD-tree seems like overkill.

Because my program only supports spheres, I wanted to tailor the datastructure for the surface of a sphere. Spatial partitioning (like KD-tree) still seemed like the way to go and I wanted to split the surface like longitude/latitude does (though unaligned to avoid aliasing at the poles). I was lazy though and didnt want to map coordinates to sphere coordinates, so instead, keeping in spirit with KD-trees, I used planes to partition the surface. By having the planes intersect the center of the sphere, they are reminicent of lat/long, and I believe I still take advantage of the knowledge that the photons lay on the surface.

Radius Search

Photon maps are queried for every ray cast during rendering. This makes this algorithm critical to performance of the program. I started by implementing an N nearest neigbors algorithm as suggested by the original creaters of the photon map. This seemed ok performance wise for small a small N (on the order of 10), but the renderings were very noisy, regardless of the number of photons with < ~1000 photons sampled, and my N nearest neighbors algorithm could not scale that high. So instead I scrapped nearest neighbors and implemented a radius search, returning all photons within a certain radius of the search point. This implementation gave the rendering an order of magnitude speedup, allowing it to sample enough photons to elliminate the worst of the noise.

Implementation Shortcuts

Quick and dirty implementations in the interest of time




Nearest Photon: 8s

0.05 Radius Search (~50 nearest photons): 8.5s

Nearest 100 Photons: 1m8s

0.1 Radius Search (~200 nearest photons): 15s

Sweet spot is somewhere is here. Too few photons and its noisy, to many and its blurry.

0.25 Radius Search (~1110 nearest photons): 58s

0.5 Radius Search (~3750 nearest photons): 3m31s