Currently, I am in my third term of my Masters of Engineering degree at the University of Waterloo. This term, I decided to enrol in CS 688 - Introduction to Computer Graphics.

As part of the course, we are required to create a project to demonstrate our grasp of computer graphics and implement graphic algorithms. We define our own list of ten objectives.

I decided to create expand on the ray tracer created in Assignment 4 and implement more advanced techniques. Here are a list of the ten objectives (and few extra) that I implemented.

# Objective zero: Jittered Supersampled Antialiasing

The extra feature I implemented for Assignment 4 was jittered supersampling.

Jittered Supersampling. This was the scene I used for my A4 submission.

# Objective one: Cone and Cylinder Primitives

Cones and cylinders were added to expand the set of primitives from Assignment 4.

Cone and Cylinder Primitives.

Instead of using the normal of the vertex, the normal was interpolated using barycentric coordinates.

Phong Shading of a classic Utah Teapot.

# Objective three: Mirror Reflection

Recursively calculate color contributions from the reflected ray. The reflected ray was calculated using the equation:

Mirror Reflection.

# Objective four: Refraction

Recursively calculate color contributions from refraction. The refracted ray was calculated using the equation:

Refraction. Three glass spheres and a cylinder with an index of refraction of 1.5.

For this objective, I needed to introduce area lighting. From each intersection point, multiple shadow rays would be cast from the intersection to a random point on the area light source.

Soft Shadows. Used a square area light with a 5x5 grid of jittered shadow rays.

# Objective six: Constructive Solid Geometry

Union, intersection, and difference operations.

Constructive Solid Geometry. Union operation on the left, intersection operation on top, difference operations on bottom and right.

# Objective seven: Texture Mapping

Texture mapping was done by calculating the UV-coordinates for primitives. Bilinear interpolation was used as the filtering method for determining the pixel color.

Texture Mapping. A texture of a globe on a sphere and a brick on a cube.

# Objective eight: Glossy Reflection

Glossy reflection was implemented by distributing multiple reflection rays from a reflective surface. Each reflection ray is perturbed following a cosine distribution as follows:

Where $\alpha$ is the polar angle, $\beta$ is the azimuthal angle, $N_p$ is the Phong exponent, and $x_1$ and $x_2$ are uniform random numbers between 0 and 1.

Glossy Reflection. Used 10 perturbed reflection rays at each reflection point.

# Objective nine: Depth of Field

Depth of field was implemented by distributing rays so that their origin are randomly sampled on a disk at the eye point of a given aperture radius.

In the following images, the aperture radius was set to 25 and the spheres have a radius of 50. 3x3 jittered samples on a disk were generated for each pixel. The eye was placed at a z value of 500. The back ball was placed at -200. The center ball was placed at 0. The front ball was placed at 200.

Top Left: Without Depth of Field.
Top Right: Focal plane is set so that the back ball is in focus. Focal distance = 700.
Bottom Left: Focal plane is set so that the middle ball is in focus. Focal distance = 500.
Bottom Right: Focal plane is set so that the front ball is in focus. Focal distance = 300.

Multithreading was implemented by parallelizing each pixel. Here’s a graph of the running time versus number of threads for the macho-cows.lua scene in Assignment 4. It was run in the gl29 computer in the Computer Graphics lab.

Multithreading. 512x512 rendering of macho_cows.lua on gl29.

# Extra Objective: Schlick Appoximation

Schlick’s approximation is a formula to approximate the Fresnel factor of specular light. It was applied to the reflected and refracted ray color contributions. It is calculated as follows (from Wikipedia):

where $cos{\theta} = \vec N \cdot \vec v$.

Schlick Approximation.

# Extra Objective: Bump Mapping

Bump mapping was implemented by reading a normal map and perturbing the normal at each surface point according to the normal map. Code from texture mapping for retrieving a pixel value for a given normal texture was reused.

Bump Mapping. Applied to same globe and brick objects in the texture mapping objective.

# Extra Objective: Motion Blur

Motion blur was implemented by giving each ray a random time value and each object a velocity. The time value and velocity together translates the object into a new location. Since we are distributing multiple rays per pixel from anti aliasing already, we get a nice averaging effect for motion blur.

Motion Blur.

# Objective ten: Final Scene

Here is my final scene with all objectives enabled.

Final Scene. With depth of field toward center of the room.

Final Scene.