My fourth-year ray tracer project

Even back then, I loved pool

My fourth-year ray tracer project

When I attended the University of Waterloo 20-ish years ago, all of the Computer Science undergrads, myself included, feared the so-called “Big 3,” courses that were so hard as to drive students mad: Real-time Programming, Compilers, and Computer Graphics.

When it came time to select my courses for fourth year, I knew I wanted to try one of them. I had a friend who dreamed of one day working on video games, so we decided to take the Graphics course together.

The final project involved creating a ray tracer. After feverishly writing code for weeks, and a lot of time waiting for images to render, the final submission took the form of an image gallery. I remember being very proud of what I’d made. I still have all of the files, and there’s no point keeping them hidden in the digital attic, so here I present my final project for CS488.

(Aside: the thumbnail image for this post that you see above was AI-generated by Stable Diffusion using the prompt: a cow carved out of wood, 3d render.)


New primitives

New cylinder and cone primitives were created.

The radius and height of the primitives can be adjusted to create a variety of shapes.

Reflections

This image shows reflections. The good ol’ “hallway of mirrors”…

This time, the ball itself is reflective, too.

Refraction

The following sequence shows a refractive pane of glass with progressively larger indices of refraction.

Refraction index 1.0 - Light rays do not get bent at all.

Texture mapping with images

Texture maps can be applied to all primitives except polygonal meshes.


Texture mapping with Perlin noise

Perlin noise functions create pseudorandom textures. The noise functions can be used to achieve many types of textures:

Pure noise

“Pure” noise gives a sort of dirty look to the texture. Different values for the persistence parameter achieves varying levels of noisiness.

I have implemented Perlin noise to allow flexibility in the colours that the texture is made of. Here is an example of using different colours:

Wood grain

Perlin noise can be used to generate wood grain textures. Wood textures work best with low values for persistence; otherwise, the grain is much too chaotic.

We can still specify colours for wood grain textures. So, it is possible to create this “psychedelic” wood:

Marble

Marble textures can be created with Perlin noise. Marble looks best with high values of persistence. Also, it looks most natural if the two colours of the texture are close in shade.

Perlin noise can be applied to all primitives, as demonstrated here.

It is very difficult to texture map an arbitrary 2-dimensional image to an arbitrary 3-dimensional shape. However, since Perlin noise is defined in 3 dimensions, it is possible to texture map complex polygonal meshes with noise. Here, we see a mesh model textured mapped with wood grain and marble textures.

Soft Shadows

Soft shadows can be created using area lights. Area lights can be partially blocked by objects, which gives the shadow a penumbra and umbra.

For comparison, this is what a “hard” shadow looks like, as created by a single point light source.

Area lights are specified as an n x n array of lights. The larger the value of n, the better the shadow will look.

The size of the light can also be changed. Larger lights cast softer shadows, and smaller lights cast harder shadows.

The size of the light can vary in either direction. Compare these two images: one is a “wide” light, and the other is a “tall” light.

Glossiness

Glossy reflections are accomplished by distributing a reflection among many reflection rays. The more reflection rays there are, the better the reflection will look.

For comparison, this is a pure, non-glossy reflection.

The following sequence shows the effect of increasing the number of rays.

We can control how scattered the reflection rays are. This is determined by the specular reflection coefficient of the material. The higher the specular coefficient, the sharper the reflection.

Final Scene

My final scene depicts a pool room. Texture mapping is used for most of the objects, most obviously on the walls, and in the painting. The frame of the table is texture-mapped with wood grain generated from Perlin noise. Notice also that the surface of the table is not completely uniform in colour; this was also accomplished with Perlin noise.

Homemade texture for the balls

This is a close-up rendering of the table which more clearly displays the reflectiveness of the balls. Also, area lights were used to render this scene.

Albert

About Me

Hi! Albert here. Canadian. Chinese.

Writing software since 2001. “Blogging” since 2004. Reading since forever.

You can find me on socials with the links below, or contact me here.