How to make a Photon Mapper : Photons everywhere

Hello,

It has been a long time since I posted anything on this blog, I am so sorry about it.
I will try to diversify my blog, I’ll talk about C++, Rendering (always <3), and Qt, a framework I love.

So, in this last part, we will talk about photons.

What exactly are Photons ?

A photon is a quantum of light. It carries the light straightforwardly on the medium. Thanks to it, we can see objects etc.

How could we transform photons in a “visible value” like RGB color ?

We saw that the eyes only “see” the radiance !
So we have to transform our photons in radiance.

From physic of photons

We know that one photon have for energy :

$\displaystyle{}E_{\lambda}={h\nu}=\frac{hc}{\lambda}$

where $\lambda$ is the wavelength in nm and $E$ in Joules.
Say we have $n_\lambda$ photons of $E_{\lambda}$ each.
We can lay the luminous energy right now :

$\displaystyle{Q_{\lambda}=n_{\lambda}E{\lambda}}$

The luminous flux is just the temporal derivative about the luminous energy :

$\displaystyle{\phi_{\lambda}=\frac{dQ_{\lambda}}{dt}}$

The idea is great, but we have a luminous flux function of the wavelength, but the radiance is waiting for a general luminous flux
So, we want to have a general flux which is the integral over all wavelengths in the visible spectrum of the $\lambda$ luminous flux.

$\displaystyle{\phi=\int_{380}^{750}d\phi_{\lambda}=\int_{380}^{750}\frac{\partial \phi_{\lambda}}{\partial\lambda}d\lambda}$

Now, we have the radiance

$\displaystyle{L=\frac{d^2 \phi}{cos \theta dAd\omega}=\frac{d^2(\int_{380}^{750}\frac{\partial \phi_{\lambda}}{\partial \lambda}d\lambda)}{cos(\theta)dAd\omega}=\int_{380}^{750}\frac{d^3\phi_{\lambda}}{cos(\theta)dAd\omega d\lambda}d\lambda}$

Using the rendering equation, we get two forms :

$\displaystyle{L^O=\int_{380}^{750}\int_{\Omega^+}fr(\mathbf{x}, \omega_i,\omega_o,\lambda)\frac{d^3\phi_{\lambda}}{dAd\lambda}d\lambda}$
$\displaystyle{\int_{\Omega^+}fr(\mathbf{x}, \omega_i,\omega_o)\frac{d^2\phi}{dA}}$

The first one take care about dispersion since the second doesn’t.
In this post, I am not going to use the first one, but I could write an article about it latter.

Let’s make our Photon Mapper

What do we need ?

We need a Light which emits photons, so we could add a function “emitPhotons” .

We also need a material which bounces photons :

Obviously, we also need a structure for our photons. This structure should be able to store photons and compute irradiance at a given position.

How could we do this ?

Photon emitting is really easy :

We divide the total flux by the number of photons and we compute a random direction, then we could trace the photon

Bouncing a photon depends on your material :

To take care about conservation of energy, we play Russian roulette.
Obviously, to take care about conservation of energy, we have to modify the direct lighting as well ^^.

Finally, we need to compute the irradiance at a given position :
It is only :

$\displaystyle{E=\sum \frac {\phi}{\pi r^2}}$

So we could easily write :

To have shadows, you could emit shadow photons like this :

That’s all ! If you have any question, please, let me know !

How to make a Photon Mapper : Whitted Ray Tracer

Hello there,

Today, we are going to see how to make the first part of our photon mapper. We are unfortunately not going to talk about photons, but only about normal ray tracing.

This is ugly !!! There is no shadow…

It is utterly wanted, shadows will be draw by photon mapping with opposite flux. We will see that in the next article.

Introduction

In this chapter, we are going to see one implementation for a whitted ray tracer

Direct Lighting

Direct lighting equation could be exprimed by :

$\displaystyle{L_o(\mathbf{x}, \vec{\omega_o}) = \sum_{i\in \{Lights\}}f_r(\mathbf{x}, \vec{\omega_i}, \vec{\omega_o})\frac{\phi_{Light}}{\Omega r^2}cos(\theta)}$

The main difficult is to compute the solid angle $\Omega$.
For a simple isotropic spot light, the solid angle could be compute as :

$\displaystyle{\Omega=\int_{0}^{angleCutOff}\int_{0}^{2\pi}sin(\theta)d\theta d\phi =-2\pi(cos(angleCutOff)-1)}$

with :

1. $\Omega$ the solid angle.
2. $\phi_{Light}$ the total flux carried by the light.
3. $cos(\theta)$ the attenuation get by projected light area on lighted surface area.
4. angleCutOff $\in [0; pi]$.

Refraction and reflection

Both are drawn by normal ray tracing.

Architecture

Now, we are going to see how our ray tracer works :

Shapes :

Shapes are bases of renderer. Without any shapes, you can’t have any render. We can have many differents shape, so, we can use one object approach for our shapes.

Materials

For each shapes, we obviously have a particular material. The material have to give us a brdf and can reflect radiance.

Storage Shapes

To have a better ray tracing algorithm, we could use a spatial structure like Kd-tree or other like one :

Algorithm

The main algorithm part is on the materials side. Below, a piece of code where I compute the reflected radiance for a lambertian material and a mirror. You could see that material part has access to other shape via the global variable world.

Lights

Lighting is a useful feature in a render. It’s thanks to lights that you can see the relief. A light carry a flux. Irradiance is the flux received by a surface.

So, our interface is :

Below a piece of code about computing irradiance :

The next time, we will see how to integrate a photon mapper to our photon mapper. If you want to have the complete code, you could get it here :
GitHub

Bye my friends :).