Contents

Lecture 3: The Rendering Equation

Note
The figures in this post were taken from the corresponding lecture slides. You can view the original lecture here.

The rendering equation describes all of the light scattering in a scene. It was originally introduced by Jim Kajiya in 1986. In rendering, we can make use of the rendering equation to mathematically describe the color that our sensor should see for every pixel. But before diving into the rendering equation, consider how a camera captures a scene in real life (under the abstraction of treating light as rays). At any given moment, a light source in the scene may be emitting trillions (or easily more) light rays that are bouncing around the scene until just a small portion travel through the camera lens and onto the sensor, at which point the measured radiance is converted to the corresponding RGB values for each pixel. Simulating so many light rays when only a few may actually reach the camera is wasteful. Instead, since the attenuation of light as it bounces on each surface is multiplicative, and since multiplication is commutative, we can reverse the order: shoot rays directly from the sensor into the scene and trace them until they terminate by hitting a light or miss all objects in the scene.

Note
Technically, we can actually let the light bounce around the scene and then importance sample the camera sensor or even trace paths from both the sensor and the lights and connect the paths, as is done with bidirectional path tracing – but that’s for another time.

So, how can we use the rendering equation to determine the color of each pixel, accounting for all the light scattering? There are three formulations of the rendering equation presented below which should help build an intuition, while also laying the groundwork for more complex integration methods.

The Recursive Formulation

This is the form the rendering equation was originally presented in and the way it is most commonly implemented. As the name suggest, it relies on recursively defining the illumination at each vertex of a light path with its own integral.

\begin{align} L_e(\mathrm{x}, v) = E(\mathrm{x}, v) + \int_\Omega f_r(\mathrm{x}, \omega, v) L_i(\mathrm{x}, \omega) \cos(\theta_x) \mathrm{d}\omega \end{align}

where

  • $L_e(\mathrm{x}, v)$ is the light going in direction $v$ from point $\mathrm{x}$
  • $E(\mathrm{x}, v)$ is the light emitted from $\mathrm{x}$ in direction $v$
  • $f_r(\mathrm{x}, \omega, v)$ is the material BRDF for hit position $\mathrm{x}$ with incoming light direction $\omega$ and outgoing light direction $v$
  • $L_i(\mathrm{x}, \omega)$ is the light arriving at point $\mathrm{x}$ from direction $\omega$
    • This is the term that is recursively evaluated!

To examine this form more closely, consider the following set up where we have two ray bounces at positions $\mathrm{x}_1$ and $\mathrm{x}_2$ with the view vector $v$ and the ray-bounce direction vectors $\omega_1$, $\omega_2$, and $\omega$, as seen in the diagram below.

./images/recursive_bounce.png
Two bounces in the recursive formulation of the rendering equation.

Now, we switch up the notation a bit, such that we use arrows to represent the direction of light travel. E.g., $L_e(\mathrm{x} \rightarrow v)$ represents light from point $\mathrm{x}$ traveling in direction $v$ and $f_r(\mathrm{x}, \omega \rightarrow v)$ represents the incoming light direction $\omega$ being converted to outgoing light direction $v$. The recursive formulation for the scenario described above can now be expressed as:

\begin{align} L(\mathrm{x}_1 \rightarrow v) = E(\mathrm{x}_1 \rightarrow v) + \int_{\Omega_1} f_r(\mathrm{x}_1, \omega_1 \rightarrow v) L(\mathrm{x}_1 \leftarrow \omega_1) \cos(\theta_{\mathrm{x}_1}) \mathrm{d}\omega \end{align}

Here, $L(\mathrm{x}_1 \leftarrow \omega_1)$ represents light recieved at $\mathrm{x}_1$ from direction $\omega_1$. But what is $L(\mathrm{x}_1 \leftarrow \omega_1)$? You may intuitively say that it should be equivalent to $L(\mathrm{x}_2 \rightarrow \omega_2)$, i.e., the light reflected from $\mathrm{x}_2$ in direction $\omega_2 = - \omega_1$, and that inuition is correct. Let’s take a short detour to see why.

Consider two small surface patches $\mathrm{d}A_1$ and $\mathrm{d}A_2$ as in the figure below, and the amount of light recieved by both surface patches from the other patch. Because we know photons travel in straight paths (under the assumptions we use for rendering) and in this example, there are no participating media, the flux $\mathrm{d}\Phi$ arriving at both surfaces from the opposing surface must be equivalent such that $\mathrm{d}\Phi_1 = \mathrm{d}\Phi_2 = \mathrm{d}\Phi$. We can model this flux as:

\begin{align} \mathrm{d}\Phi &= L(\mathrm{x}_2 \rightarrow \omega_2) \cos(\theta_{\mathrm{x}_2}) \mathrm{d}A_2 \frac{\mathrm{d}A_1 \cos(\theta_{\mathrm{x}_1})}{r^2}\\ \mathrm{d}\Phi &= L(\mathrm{x}_1 \leftarrow \omega_1) \cos(\theta_{\mathrm{x}_1}) \mathrm{d}A_1 \frac{\mathrm{d}A_2 \cos(\theta_{\mathrm{x}_2})}{r^2} \end{align}

As you can see, all the terms except $L(\mathrm{x}_2 \rightarrow \omega_2)$ and $L(\mathrm{x}_1 \leftarrow \omega_1)$ are equivalent. Therefore, it must be the case that $L(\mathrm{x}_2 \rightarrow \omega_2) = L(\mathrm{x}_1 \leftarrow \omega_1)$.

./images/light_constancy.png
The amount of light recieved on surface patch dA1 from surface patch dA2 is equivalent to the amount of light reflected from surface patch dA2 towards patch dA1.

Okay, back to the recursive integral. Now, we can recursively define $L(\mathrm{x}_1 \leftarrow \omega_1)$ as:

\begin{align} L(\mathrm{x}_2 \rightarrow \omega_2) = E(\mathrm{x}_2 \rightarrow \omega_2) + \int_{\Omega_2} f_r(\mathrm{x}_1, \omega \rightarrow \omega_2) L(\mathrm{x}_2 \leftarrow \omega) \cos(\theta_{\mathrm{x}_2}) \mathrm{d}\omega \end{align}

And likewise, we can now recursively define $L(\mathrm{x}_2 \leftarrow \omega)$. This process keeps repeating until we terminate the ray.

How should we evaluate these integrals? Actually integrating the entire hemisphere at every intersection point of every possible ray path is an infinite-dimensional problem! Instead, in the spirit of Monte Carlo techniques, we instead just choose a single sample direction at each intersection. This is the approach used in most path tracers. Note however, that you can also evaluate more samples at each intersection if you wanted to. For instance, you can cast shadow rays at each intersection while still evaluating multiple ray bounces for the primary ray path. Just make sure to scale your samples accordingly. We’ll cover such importance sampling techniques later.

The Operator Formulation

Under construction…

The Path Integral Formulation

Under construction…