RAY Tracer
The CPU Ray Tracer was one of the first projects that I had to make during my study.
The goal of the ray tracer was to improve your mathematics while also strengthening your C++ skills and to get your familiar with the rendering pipeline.
Within the project, I was able to ray tracer spheres that were either solid, reflective, or refractive.
The ray tracer also includes point lights, a moving camera and makes use of a BVH to increase the performance of the ray tracer.
Graphics Programmer
Solo
8 weeks
Windows
Custom Engine
SDL
Ray Tracer
To make the ray tracer interesting, I added a few material types to show its effect. Those include: opaque,
reflection and refraction. Besides those, material color was also added to change the effect.
Opaque: the opaque object within the scene is very basic, and simply traces the rays from the screen
towards the light source, while also taking the material color into account to display the correct color.
A Specular was also added for additional effect where the lights focus is the strongest.
Reflection: the reflective objects within the scene are a bit more interesting, as the rays don’t go directly towards the light source, but rather follow a certain angle depending on where the camera is. From there, the ray would hit a mat object and trace back to the light source. Resulting in a reflective material. Depending on how reflective a material is, it might retain some of its original color.
Refraction: the refractive objects in the scene act similar to the reflections but split the rays in 2.
Where one ray would reflect and the other would refract into the refractive material. The ray that’s
inside the refractive material would continue to split in two, where one ray would stay inside and the
other would continue outside to trace back to the light source.
As continuous refraction is impossible to calculate, a hard cap has been added to stop the rays from refracting.
Depending on the refraction value of the object, the result will also differ. As water has a different
fraction value compared to glass for example.
When firing a ray from the screen towards an object in the scene back to a light source. It might happen that another object blocks this path. In these cases the pixel would turn black as it became a occluded, and is now a shadow. Although this will result in hard shadows. They could be made softer to result in more realistic shadows.
Code snippit of the ray tracer renderer in C++
Optimizations
One optimization technique that I applied to my CPU ray tracer was the implementation of a
Bounding Volume Hierarchy (BVH).
Using the BVH, I would turn the objects within the scene into leaves that follow back to a root.
This would optimize the ray tracer by only having to check if a ray hit a single root, rather than an individual object. Thus, reducing the cycles needed to check if the rays hit something.
Although not implemented in the project, one optimization technique that I could implemented would be multithreading
for different sections of the screen. Some other techniques would also include making use of SIMD to run calculations
in parallel without multiple threads. And to add noise to reduce the amount of rays to be fired.
Code snippit of the BVH
Code snippit of the BVH nodes
Math Library
One of the challenges that we had for this project, was that we had to write a ray tracer without
the use of any existing math libraries like GLM. Instead, we had to make our own math library to
brush up our math skills.
The math library would then continue to be used within the ray tracer itself, showing the understand
of both the ray tracer and the mathematics involved in it.
Code snippit of vector3 class in the math library
Unit Tests
As I had to make sure that my math library was stable enough to be used for my own ray tracer,
I had to write unit tests to demonstrate that the results were correct using Google Test.
This was done by using external calculators to calculate a specific formula, and then use my
own math library to calculate the same formula. If the answers were the same, I knew that the function was correct.