During the develeopment of this project, I learned the fundamentals of graphics programming. I created a raytracer on the CPU that supports following features:
Render primitives, such as planes and spheres, as well as meshes.
Render hard shadows.
Make use of Physically Based Rendering (PBR).
In the scene, it is possible to move around with the camera and adjust the FOV utilising matrices.
The rendering equation determines what the outgoing randiance is on an object.
To simulate where a light hits an object, we calculate the observed area. By calculating the Dot product on the opposite light direction with the hit point normal, we have the value that represents how direct the light hits the hit point. To visualise the observed area, you add those values gathered from all the lights.
Based on the color and intensity of the lights, we can calculate the radiance they cause on the objects.
First calculate the squared magnitude of the light direction to the hit point. Then, multiply the light intensity by the light color and divide by the magnitude.
float sqM = (light.origin - hitPoint).SqrMagnitude();
Color radiance = light.intensity * light.color / sqM;
BRDF stands for 'Bidirectional Reflectance Distribution Function'. There are lots of different BRDF's out there, they all handle the distribution or scattering of
light based on an objects material. For the spheres, I use a Cook Torrence BRDF which applies the Trowbridge-Reitz GGX Normal Distribution function, the Schlick Fresnel function and the Schlick-GGX Geometry function. It also takes metalness into account.
For triangles we need to apply the same method as with planes (Dotting the ray directon with the plane normal), but we need to do some extra checks. By using the Dot product for every side of the triangle, we can check if the ray direction lands outside of the triangle.
You can apply Front Face Culling and Back Face Culling based on whether the Dot pruduct with the normal is negative or positive.
Since we can render 1 triangle, we can render multiple. So we can load in .obj files and render meshes.