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.

You can download all the images here.

# 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.

# Objective two: Phong Shading

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.

# Objective five: Soft Shadows

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.

# Extra Objective: Multithreading

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.