Skip to content
Class assignment for CPE 473
POV-Ray SDL C++ Other
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


Class assignment for CPE 473

Software Design

One componet of my ray tracer project that I am particularly proud of was my implementation of a BVH (Bounding Volume Hierarchy). I took advantage of a software design pattern called the Composite Pattern that let me easily add support for this spatial data structure.

The base class I used was the Geometry abstract class. This was the parent class for all shapes in the scene including Triagle, Sphere, Plane, and AABox.

Geometry has an abstract method get_intersection that returns an intersection object based off of a ray. Each shape had a concrete implementation of this.

Until now, this has been basic OOP inheritance. The magic was created when I added the BVH class as a subclass of AABox. BVH is an axis-aligned box that holds a vector of shapes that it completely surrounds. I then override the get_intersection method to:

  1. call the super class (AABox) intersection to see if a ray could intersect any of the shapes.
  2. check if there is an intersection with the BVH
  3. if there isn't return null.
  4. iterate through the shapes and call their get_intersection methods.
  5. return the closest intersection.

Since BVH is ultimately a descendant of Geometry, a single root to the BVH tree could be put inside the Scene class's list of shapes, and calling get_intersection on that root BVH would cleanly traverse the whole BVH tree to find the intersection point.

The structure is explained in this class diagram

class diagram

Final Project: Ambient Occlusion

Ambient occlusion is a technique for approximating shadows when determining the ambient light component for local shading. This is done by casting several rays in a hemisphere around the normal from a incident ray's intersection point. The ambient light component is then divided by the number of these rays that actually intersect something in the scene.

The Monte Carlo ambient lighting technique already provides a mechanism for casting these rays in a hemisphere, so I leveraged that code. The only modification was simply counting the number of these rays that hit another object. I then divided the ambient lighting component by this count.

The reason that this works is because when a hemisphere of random rays are cast where two objects are close together, many of these rays will intersect with another object. This reduces the ambient contribution to local shading and provides a good approximation of shadows.


Below are some examples of the same image with and without ambient occlusion and monte carlo global illumination.

Neither GI AO Both

Resources for Implementing Ambient Occlusion

  1. renderWiki
  2. wikipedia
You can’t perform that action at this time.