Photon Map Source Code

Photon maps are a great way of calculating global illumination. They're fast simple, and look great. If you've got a renderer that can ray trace, then you can add simple photon mapping in a few hours, and have it fully integrated in a few days.

To make thinks even easier, here's the code you need to create, load, save and access the photon map data structures. They're 90% based on Henrik Jensen's code form his excellent book on photon mapping, though I've added a few refinements of my own to make the whole process is idiot-proof as possible.

Using the code

Create a map by calling PhotonMap *map=createPhotonMap(100000);. Don't worry about the exact size of the map - it's just an estimate, and the code will automatically resize it as necessary.

To add a photon to the map call:

storePhoton(PhotonMap *map,
    const float power[3],          // photon power
    const float pos[3],            // photon position
    const float dir[3]);           // photon direction

Once you've put all the photons into the map, you need to balance it before you can use it: BalancedPhotonMap *bmap=balancePhotonMap(PhotonMap *map);. This destroys the original map, and returns a new balanced map, which you can then do lookups in (actually it doesn't - the type change is just a trick to stop you forgetting to balance the map).

At this point you probably want to save the map, and load it back in latter when rendering the beauty pass.

void savePhotonMap(BalancedPhotonMap *bmap,char *filename);
BalancedPhotonMap * loadPhotonMap(char *filename);

To look up the irradiance from a balanced map you can use:

void irradianceEstimate(
  BalancedPhotonMap *map,
  float irrad[3],                // returned irradiance
  const float pos[3],            // surface position
  const float normal[3],         // surface normal at pos
  const float max_dist,          // max distance to look for photons
  const int nphotons );          // number of photons to use
Unfortunaty this requires both a maximum number of photons, and a maximum search distance used to prune the search. I found this inconvenient, as I didn't always know the scale on which I was operating, so added:
void autoIrradianceEstimate(
  BalancedPhotonMap *map,
  float irrad[3],                // returned irradiance
  const float pos[3],            // surface position
  const float normal[3],         // surface normal at pos
  const int nphotons );
which guesses the distance, and will have another go if it gets it very wrong. This version is probably slower, and produces more artifacts than the previous version provided you have a good estimate of distance, but it's much easier to drop in to the renderer.

Finally destroy your map with: void destroyPhotonMap(BalancedPhotonMap *map);

Note that this code doesn't know anything about the coordinate system being used, so you may need to consider what frame of reference your photon maps should be stored in. World space is probably theoretically optimal, but as for all shading calculations, this would require and extra transformation for every point shaded. Angel stores it's maps in camera space.



Feel free to use this code as you see fit - as I didn't write most of it, then I can't really place any restrictions on it. However I would appreciate an email telling me what you're doing with it, and a credit in the documentation of your app. Bug fixes and improvements are welcomed. If you can avoid changing the file format, that would be usefull as then you'll be able to use maps generated in Angel, and visa vera. I'd also sugguest that if you use it, you should probably buy Jensen's book, as it's based on that code.

Ian Stephenson.
DCT Systems
NCCA,Bournemouth University