up to Schedule & Notes

Photon Maps

Problem: Specular reflection and refractive transmission from the light is not seen in standard raytracing.

Caustics are concentrations of light from reflection and transmission. Two examples are shown below, from the work of Henrik Wann Jensen: "Global Illumination using Photon Maps" in Eurographics Rendering Workshop 1996, pp 21-30.

Idea: Cast photons from the light and store them where they hit a surface. When later casting rays from the eye, look up these stored photons and use them in the lighting calculation.

A photon map is a data structure that records where photons from the light land on diffuse surfaces.

Photon Mapping

Perform three steps:

  1. Cast photons from each point light source. Let them reflect and refract. Record where the photons land on each surface.
  2. For each surface, build a 2D kd-tree to store the photons for quick lookup. Alternatively, build a single 3D kd-tree for the whole scene.
  3. Do normal raytracing but, at each ray/surface intersection, look up in the kd-tree to find photons close to the ray/surface intersection. Incorporate those photons into the lighting calculation.

Step 1

Each photon is a small data structure that stores

  • power (in r,g,b components with at most 1.0 for each component)
  • arrival direction (from which the photon arrives at a surface)
  • position (on the surface where the photon lands)

Send photons in random directions from the lights. Use standard raytracing to follow photons through the scene. Upon a photon/surface hit, do only one of

  • $s$: reflect specularly
  • $d$: reflect diffusely in a random direction
  • $t$: refract

The choice of event, from the three events above, is done probabilistically, with $s, d, t$ being the probability of each event. These probabilities could be $$\begin{array}{l} \displaystyle s = \alpha \; { \max( k_s ) \over \max( k_s ) + \max( k_d ) }\\ \displaystyle d = \alpha \; { \max( k_d ) \over \max( k_s ) + \max( k_d ) }\\ \displaystyle t = 1 - \alpha \\ \end{array}$$

where $k_s, k_d, \alpha$ are the material properties at the ray/surface intersection point and "max" is the maximum of the rgb components.

You should, as always, ensure that $\max(k_s) + \max(k_d) \le 1$ in your material properties.

A photon is stored on a surface if

  • the photon has made at least one refraction or specular reflection
  • and subsequently arrives from above
  • at a diffuse surface (i.e. a surface with some component of $k_d$ being non-zero).

Once the photon is stored on a surface, raytracing of that photon stops. Raytracing also stops if the photon has made more than some predetermined number of bounces.

Step 2

Build a kd-tree to hold the photons that have been collected on each surface. A separate 2D kd-tree can used on each surface, or a single 3D kd-tree can be used for the whole scene.

A kd-tree node represents an axis-aligned box. On a surface, for example, this is a 2D box:

The box is split such that half of its photons go into each child. Choose a median photon to define the split position:

Recurse so that each leaf holds no more than some maximum number of photons. Each level of the hierarchy alternates the split axis from $x$, then to $y$, then to $x$ again, then to $y$ again, and so on:

The kd-tree data structure must also provide a function that returns all photons within a distance, $r$, of a position, $x$.

Step 3

Perform normal raytracing from the eye. At each bounce, query the kd-tree for photons near the bounce point (i.e. the ray/surface intersection point). Consider each of these photons as coming from an additional light source and incorporate them into the Phong model.

Below, $x$ is the bounce point, $C$ is a circle on the surface of radius $r$ around $x$, and each photon (with an arrow for its arrival direction) is shown in red. A query would return the three photons inside the circle.

The rendering equation states that $$L(x,\omega_o) = \int_\Omega f(\omega_i, \omega_o) \; L(x,\omega_i) \; \cos\theta_i \; d\omega_i$$

where:

  • $x$ is the point at which we are calculating the outgoing light;
  • $\omega_o$ is the direction of the outgoing light;
  • $\omega_i$ is a direction from which light arrives;
  • $L(x,\omega_o)$ is the radiance leaving the point $x$ in direction $\omega_o$;
  • $L(x,\omega_i)$ is the radiance arriving at $x$ from direction $\omega_i$;
  • $\Omega$ is the hemisphere of directions above the surface at $x$ from which light arrives;
  • $f(\omega_i,\omega_o)$ is the fraction of light reflected from $\omega_i$ to $\omega_o$, per solid angle, and is often modelled with Phong using $\omega_i$ as the incoming direction and $\omega_o$ as the eye direction; and
  • $\cos\theta_i$ is the attenuation of incoming light as it is spread out over the surface at $x$.

Discretizing and approximating results in $$\begin{array}{rl} L_\textrm{out}(x,\omega_o) & = \displaystyle \int_\Omega f(\omega_i, \omega_o) \; L(\omega_i) \; \cos\theta_i \; d\omega_i \\ & \displaystyle \approx \sum_{p_i \in C} f(\omega_i,\omega_0) \; L(p_i) \; \cos\theta_i \; \Delta\omega_i \\ & = \displaystyle \sum_{p_i \in C} f(\omega_i,\omega_0) \; { P_i \over \Delta\omega_i \; \cos\theta_i \; \Delta A} \; \cos\theta_i \; \Delta\omega_i \\ \end{array}$$

where:

  • $C$ is the circle of radius $r$ around $x$;
  • $p_i$ is one photon in $C$;
  • $\Delta A = \pi \: r^2$ is the area around $x$; and
  • $P_i$ is the power of photon $p_i$.

Conclusion

Then $$L_\textrm{out}(x,\omega_o) \approx {1 \over \pi \: r^2} \sum_{p_i \in C} f(\omega_i,\omega_o) \; P_i$$

To compute this, take each photon in $C$ and multiply its power by $f(\omega_i,\omega_o)$, which is the faction of light coming in from direction $\omega_i$ that leaves in direction $\omega_o$, which you can calculate using the Phong model. Add up all the results and divide by $\pi \: r^2$.

However, since the number of photons in $C$ will be proportional to the number of photons that are in the kd-tree, $\mathbf{L_\textrm{out}}$ should be normalized by dividing it by the total number of photons in the photon map, then multiplying by some constant. This constant should really be chosen according to the power of the light sources, but can be chosen heuristically to get caustics of "reasonable" brightness.

This means that more photons in the area around $x$ result in more outgoing radiance.

up to Schedule & Notes