In my first year of my study program, we were assigned to make a ray tracer from scratch. No libraries, no engines, no nothing.
This ray tracer has recursive ray bouncing. It has diffuse, metallic and glass materials. It also has shading and hard shadows. The ray tracer can both render spheres and ellipsoids.
I learned much more about math for games during this project. Dot and cross product, reflections, intersections and much more.
How ray tracers work
Recursive functions
Although looking back, this code does not look great, I did improve immensely in C++ during this project. If I were to rewrite this today, I would write everything completely different. For example by moving the intersection functionality of the materials out of the switch statement, and making a virtual function on the material that manages it.
Every frame we shoot a ray for all the pixels on the screen. This will give a noisy result, which is why I trace every frame. I then take the average of the frames, so the image will get smoother and smoother over time, without causing performance issues.
In the trace function, I attempt to find the nearest sphere that the ray has hit. If it hit nothing, it returns nullptr. We then calculate the intersection point and the normal. Then depending on what material the sphere has, the ray bounces differently.Â
A diffuse material returns its color multiplied with the shadow that is calculated using the normal and the dot product of the direction to the light and the normal.
A metal material reflects the ray and recursively traces another ray, until either air, or a diffuse material is hit.
Glass partially reflects, and partially refracts, based on the Fresnel formula and the reflective index that takes in.
Eventually after all the recursion, the pixel is given a color.