Ray Tracing in C++

Exercise

Overview

As an exercise in learning the fundamentals of ray tracing and further understanding the rendering process, I wrote a ray tracing renderer in C++ from scratch, including the vector class and underlying operations. For the most part I closely followed Peter Shirley's Ray Tracing in One Weekend book, with some modifications. You can access the book here, along with some of his other very useful resources on ray tracing renderers.

Process

As a first step to make sure everything was running properly, I outputted a simple image of a color gradient based on the screen space coordinates. After this I added 3D vector and ray classes to handle the underlying mathematical operations.

The next step was to start casting rays and get some geometry actually showing up. I added a simple background gradient based on the y-coordinate of the ray's direction, and a spherical surface that returns a flat color when hit.

The surface normals are simply a ray of unit length in the direction from the sphere's center to the point of intersection with the camera ray on the surface. At this point I also added a class to manage multiple objects in the scene.

Anti-aliasing is handled by casting several rays with a slight random variation in direction for each pixel, and then averaging the colors from those samples to achieve the final color.

With all that set up, I added diffuse lighting. This is achieved by bouncing the ray off whatever surface it hits until it no longer hits anything. The more times the ray for a given pixel bounces, the darker the color in that area.

Next I created a class for material properties, and added metallic and glass-like materials. The metal uses a standard reflective model, while the glass also uses refraction based on Snell's law and Schlick's approximation.

As a final step I added camera positioning and depth of field blur. The image at the top of the page shows all the elements together in a render from the finished ray tracer.



Conclusions

In practice this ray tracer is too slow to be practical for high resolution images or smoothly sampled anti-aliasing. The images shown here were rendered at 25-50 samples and still retain a fair bit of graininess. But as an exercise in ray tracing fundamentals it's been very informative. In the future I'd like to add support for textures, other geometric shapes, and directional lighting, and I'm currently in the process of adding the ability to move the camera over time and render a turnaround shot. But for now it's a concise, functional little ray tracer with a range of basic features.