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:
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 is the polar angle, is the azimuthal angle, is the Phong exponent, and and 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):
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.
Objective ten: Final Scene
Here is my final scene with all objectives enabled.
Final Scene. With depth of field toward center of the room.