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.
© Copyright 2026 Paperzz