TNCG15: Advanced Global Illumination and Rendering, Lecture 8

TNCG15: Advanced Global Illumination and
Rendering, Lecture 8 (Photon mapping ’light’)
Mark Eric Dieckmann,
MIT, ITN
Campus Norrköping
SE-60174 Norrköping
September 27, 2016
Motivation for this lecture
◮
Monte-Carlo raytracing performs poorly when we have caustics in
the scene.
◮
We can improve the rendering with a two-pass method:
First pass: follow radiance from the light source into the scene.
Second pass: MC ray-tracing using information from the first pass.
◮
Photon mapping introduces a bias but it speeds up significantly the
rendering. We use a slimmed-down version of it.
◮
We use photon mapping only for the computation of direct light.
First pass: defining photons
We shoot radiance from a light source towards a surface, which
contributes to the irradiance at a surface point.
Radiance corresponds to the infinitesimal flux carried by one ray.
We do not deposit a finite amount of power onto the wall with single
rays and we do not want to compute irradiance.
We define ’power packets’ or photons. The total flux of all photons
equals that of the light source.
We have a triangular light source with a uniformly emitted radiance L0 .
Its radiosity is M(x) =
R
Ω
L0 cos θout dωout = πL0 .
The total flux of the light source is ΦT =
R
A
M(x) dA = πAL0 .
First pass: defining photons
We know the total flux of the light source ΦT and we distribute it over
the outgoing photons.
In the original form of the algorithm, the photons are either
* photons that are shot from the light source into random directions.
* photons that are shot towards specular reflectors.
In our project we shoot all photons into random directions.
Random direction: We pick a random point on our light source using
barycentric coordinates and a random emission direction for each photon.
The emission direction has a uniform PDF for azimuth and inclination.
We distribute the flux equally over N photons and each photon gets the
flux ΦT /N. We use a large number of photons (1-10 millions).
Direct diffuse photons
The photons that are emitted by the light source and do not hit the
mirror or the transparent object will hit a Lambertian or ON reflector.
We terminate that ray at its first intersection and we write the direction
and the flux of this photon into the photon map.
If the ray hits a surface that is not the scene wall we follow it further.
Each further intersection of this ray with a surface results in a shadow
photon and we write it into the photon map.
A shadow photon does not need a direction and flux. We tag it such that
we can distinguish it from a real photon.
Caustic photons
Some of the photons will hit the transparent object or the mirror or both.
Their path is continued using the perfect reflection / refraction laws.
We place a photon at the location where the ray is reflected. We do not
place a photon where a transmitted ray leaves a transparent object.
If the reflected or refracted photons hit a Lambertian / ON surface, their
path is terminated. Their flux and direction is stored in the photon map.
We do not get shadow photons for the ray paths of these photons:
*the mirror is in the scene wall and there is nothing behind it.
*the transparent object does not block the photon path.
Second pass: Rendering
We want to test and implement the basic ingredients of the photon map
algorithm without having to reimplement the core part of our MC code.
We replace the computation of direct light with shadow rays by a
computation based on the photon map.
The direct light is computed by
Z
Le (x → ωout ) = fr (x, ωin , ωout ) L(x ← ωin ) cos θin dωin
which we approximate in MC integration using shadow rays.
2
d Φ(x←ωin )
The definition of the radiance by L(x ← ωin ) = cos
θin dA dωin helps us with
setting up the photon map algorithm.
Z
d 2 Φ(x ← ωin )
Le (x → ωout ) = fr (x, ωin , ωout )
dωin .
dA dωin
Second pass: Rendering
We have the integral form for the direct light contribution
Z
d 2 Φ(x ← ωin )
dωin .
Le (x → ωout ) = fr (x, ωin , ωout )
dA dωin
The photon i has a fixed direction ωin,i and acts as a Dirac δ-function.
The integral over the hemisphere is reduced to a sum over the photons
multiplied with the value of the BRDF for the angles ωin,i and ωout .
We do have a limited number of photons so the reflection is evaluated in
a sphere around x with radius r that contains M photons.
Le (x → ωout ) =
M
X
i =1
fr (x, ωin,i , ωout )
Φ(xi ← ωin,i )
πr 2
Identifying the photons
We use the flux information, which is stored in the M photons that are
closest to x, where x is the point where we evaluate the direct lighting.
We identify these photons by comparing their position vector xi (position
of photon number i) with the position x.
We search for the photons within a sphere with radius r0 : the photons
2
are accepted if r 2 = ||x − xi || < r02
We keep the search radius r0 constant and get a variable number of
photons M inside this sphere. We compute
Le (x → ωout ) =
M
X
i =1
fr (x, ωin,i , ωout )
Φ(xi ← ωin,i )
πr 2
The photon maps
We determine the photons that contribute to the local lighting at a point
x by comparing their distance to a threshold distance.
If we store all photons in the same photon map, then we must compare
2
r 2 = ||x − xi || with r02 for millions of photons.
We evaluate local lighting at many surface points x: expensive.
We need to sort the photons according to their location, which results in
a data structure.
We compare the location x to the elements of this data structure and we
pick the appropriate subset.
The subset may contain hundreds of photons, which reduces the number
of computations.
Data structure
Several data structures exist. I recommend the Octree.
You start with a box that contains the entire scene.
It is easiest to align the box with the cartesian axes and to select the
minimum size along each axis that can hold the scene.
You create a class Node, which corresponds to the box. This class has
information about the box boundaries xmin , xmax , ymin , ymax , zmin , zmax .
Node has pointers to 8 objects of type Node and it has a dynamic array
for objects of the class Photon.
You copy your raw global photon map into the instance of Node that
contains the entire scene.
Data structure
You have all photons stored in one instance of Node.
You count how many photons your dynamic array contains and you
compare r0 to the size of the box along each axis.
If the number of photons is larger than a user-defined N0 (may be a few
hundred) and
if the smallest value of (xmax − xmin ), (ymax − ymin ) or (zmax − zmin ) is a few
times larger than the search radius r0
then you partition the box into 8 equal-sized instances of Node.
Your smallest box length is (zmax − zmin ) for your scene and take a ratio
(zmax − zmin )/r0 ≈ 8 − 10.
You set xmin , xmax , ymin , ymax , zmin , zmax in each child node and move the
photons from the parent node into the corresponding child node.
Data structure
You have 8 child nodes of type Node.
The parent node has filled all pointers to the child nodes and it has an
empty list for the photons.
The child nodes have pointers to photons but no child nodes.
You check for each child node if the number of photons is above your
threshold and if its size is significantly larger than r0 .
If both is true, you subdivide that particular child node. You perform the
test for each child node separately.
You apply the subdivision until all child nodes either have a number of
photons below your threshold or a size below your threshold.
The photons are stored in the bottom nodes in the tree. All other nodes
only have information about the box size, location and about the parent
/ child nodes.
Using the data structure
You want to compute direct lighting at the point x on the surface.
This point x will definitely be contained in the top node of your octree.
You have available the (x, y , z)min , (x, y , z)max of each child node.
⇒ You can easily determine the child node that contains x.
You follow the octree until you get to the smallest box that contains x.
The photons of this box are those that are close to x and are thus
relevant for the lighting calculation.
Using the data structure
We have available the photons of the box in which x is located. We use
them to compute
Le (x → ωout ) =
M
X
i =1
fr (x, ωin,i , ωout )
Φ(xi ← ωin,i )
πr 2
if three conditions are fulfilled:
1. M > M0 , where you should select a value M0 ≥ 10.
2. The child node does not contain shadow photons.
3. The point x is farther away from the box boundaries than r0 .
If one of these conditions is not fulfilled, then you use the MC algorithm
to compute direct light with shadow rays.
You could remove some of the cases where condition 3 is not fulfilled by moving up to
the parent node. If x is not close to its boundaries, then you compare x to the
positions of all photons of the parent node. That can be expensive though.
The computation
The direct light Le (x → ωout ) has been computed either by using the
photon map information or by using the MC scheme (Lecture 6).
You use the MC scheme to compute the reflected light.
You should visualize the photons and the shadow photons in your report.
You can visualize their positions as points, for example using Matlab.
You should compare the results of your mixed photon mapping / MC
integration scheme with that of a pure MC scheme for direct light.
You should give benchmarks of your photon mapping for several values of
r0 and for several values of N, which is the total number of photons. You
should also show the result.
Note that your photon mapping scheme will be better than the MC scheme if
your camera sees caustics. Your mirror should give one on the floor and you
may get one from a transparent sphere if you place it in the right place.