Assignment 3: PathTracer

Michael Lu

Part 1: Ray Generation and Intersection

For reflection, I simply negate the x and y coordinate values to reflect across the normal. For refraction, I convert to spherical coordinates in order to generate the appropriate refraction ray, scaled by the ior variable depending on whether the ray enters or leaves the object. For the Mirror BDSF, I reflect the incoming ray and then return the reflectance scaled by the cosine term. For the Glass BDSF, if the ray does not refract, it reflects, otherwise I calculate the Fresnel coefficient and reflect or refract probabilistically.

Also I have no idea why my refraction looks like this. I've spent a long time trying to figure out why but to no avail.




Spheres: depth 0 (-s 64 -l 4)
Spheres: depth 1 (-s 64 -l 4)
Spheres: depth 2 (-s 64 -l 4)
Spheres: depth 3 (-s 64 -l 4)
Spheres: depth 4 (-s 64 -l 4)
Spheres: depth 5 (-s 64 -l 4)
Spheres: depth 100 (-s 64 -l 4)

At depth zero, we have the direct light sources. At depth 1, we add the one bounce non-delta surface raytrace paths. At depth 2, we add the two bounce non-delta surfaces and reflective surfaces. At depth 3, we add refraction, as well as the two bounce paths off of the reflective surface. At depth 4, we get the paths that trace through the refractive object. Afterwards, we fill out the lighting, and by depth 100, we've probably reached convergence.

Part 2: Microfacet Material

I simply applied each of the formulas in the spec for F and D. For sampling, I generated a sample for theta and phi using the inversion method and computed the associated incoming ray, applied the change of variable for the pdf, and returned the corresponding radiance value.


Dragon: alpha 0.005 (-s 128 -l 1 -m 5)
Dragon: alpha 0.05 (-s 128 -l 1 -m 5)
Dragon: alpha 0.25 (-s 128 -l 1 -m 5)
Dragon: alpha 0.5 (-s 128 -l 1 -m 5)

The lower alpha value results in a glossier surface on the dragon, whereas a higher alpha value corresponds to a shinier diffuse surface.

Bunny: cosine hemisphere sampling (-s 64 -l 1 -m 5)
Dragon: importance sampling (-s 64 -l 1 -m 5)

Since all raytrace paths originate from a light source, all samples contribute to the surface radiance. In the cosine hemisphere sampling, samples are generated randomly, leading to some samples contributing nothing, which accounts for the high variance and noise.

Spheres (-s 64 -l 1 -m 5)

I just used the scene with the aluminum and silver spheres.

Part 3: Environment Map Lights

To normalize the environment map pdf, I simply looped over the map and divided each element by the sum of all the elements. For the cumulative marginal distribution, I kept a running sum and kept track of the sums at the end of each row. For the conditional distribution, I simply looped twice over each row to compute the total in each row and then to compute the conditional distributions. For both uniform and importance sampling, I simply followed the spec instructions step by step using all the helper functions along the way.



Grace Environment Lights
Probability Distribution for grace.exr
Unlit bunny: Uniform Sampling (-s 4 -l 64)
Unlit bunny: Importance Sampling (-s 4 -l 64)
Unlit copper bunny: Uniform Sampling (-s 4 -l 64)
Unlit copper bunny: Importance Sampling (-s 4 -l 64)

In both the unlit bunny scenes, the uniform sampling renders have a significant amount of white noise that is absent from the importance sampled renders. They are also darker in general and have less apparent shadows because not all of the sampled rays are directed towards light sources and therefor will not contribute to the overall incoming radiance of each raycast.

Part 4: Depth of Field

I simply computed the pLens and pFocus based on the sampled values and then returned the ray that extends from the lens point to the focus point.


Dragon: focus depth 1.7 (-s 64 -l 4 -m 5 -b 0.0883883)
Dragon: focus depth 1.9 (-s 64 -l 4 -m 5 -b 0.0883883)
Dragon: focus depth 2.2 (-s 64 -l 4 -m 5 -b 0.0883883)
Dragon: focus depth 2.5 (-s 64 -l 4 -m 5 -b 0.0883883)

Dragon: aperture size 0.05 (-s 64 -l 4 -m 5 -d 2.5)
Dragon: aperture size 0.0833833 (-s 64 -l 4 -m 5 -d 2.5)
Dragon: aperture size 0.15 (-s 64 -l 4 -m 5 -d 2.5)
Dragon: aperture size 0.25 (-s 64 -l 4 -m 5 -d 2.5)

Part 5: Shaders

Link to my gl directory!

Vertex shaders compute the location of the vertices on the screen and fragment shaders compute the color of the pixels of a triangle on the screen based on the lighting and material properties in the scene.

In the Blinn-Phong model, we basically superpose ambient, diffuse, and specular lighting to imitate realistic lighting effects on objects.


Blinn-Phong shading model (ambient only)
Blinn-Phong shading model (diffuse only)
Blinn-Phong shading model (specular only)
Blinn-Phong shading model

Bump mapping (256 components)
Displacement mapping (256 components)
Bump mapping (64 components)
Displacement mapping (64 components)

Bump mapping changes the normal vector for vertices on the surface, so that lighting calculations account for surface bumps even though the actual surface bumps don't exist. Displacement mapping additionally moves the position of the vertices to accurately map and resemble the textured surface. In both mapping types, the surface appears smoother when decreasing the number of components.

For the custom shader, I just added the pulsing wave effect to the displacement mapping and increased the components on mesh.