Custom Raytracer (2021)
From Scratch C++ - Solo Development - 8 weeks development time - Graphics Programmer - PC
From Scratch C++ - Solo Development - 8 weeks development time - Graphics Programmer - PC
In this project, I was tasked with making a raytracer from scratch. This allowed me to develop some graphics programming skills.
I was very happy with the final result of this project as I managed to implement many material types such as lambertian, dialetric, and metallic on both Spheres and Ellipsoids.
Since this was a CPU raytracer, performance was not the best so I decided to also implement a bounding volume hierarchy.
This is a snippet of the GetPixelColor function which is the main function that gets the color to send to the screen:
color Scene::GetPixelColor(const Ray & ray, int bounces)
{
recordHit hit;
if (bounces <= 0)
return color(0, 0, 0);// The ray has bounced too many times and so no longer gets light
bvh.root->Traverse(&world, ray, hit, bvh.pool);
if (hit.mat != nullptr)// if hit a sphere from screen
{
vec3 rayDirection = ray.GetDirection();
switch (hit.mat->matType)
{
case 1:// Lambertian
{
return LambertianShading(&hit);
}
case 2:// Reflections
{
return Reflect(rayDirection, hit, bounces);
}
case 3:// Dielectrics
{
float rayDdotN = hit.normal.dot(-rayDirection);
float n1 = 1;
float n2 = 1.5f;
float n1divn2 = n1 / n2;
float k = 1 - ((n1divn2) * (n1divn2)) * (1 - rayDdotN * rayDdotN);
if (k < 0)
{
return Reflect(rayDirection, hit, bounces - 1);
}
else
{
// Fresnel equation
float sinI = sqrtf(1 - rayDdotN * rayDdotN);
float cosT = sqrtf(1 - (n1divn2 * sinI) * (n1divn2 * sinI));
float sPolarized = (rayDdotN - n2 * cosT) / (rayDdotN + n2 * cosT);
float rPolarized = (cosT - n2 * rayDdotN) / (cosT + n2 * rayDdotN);
float Fr = 0.5f * ((sPolarized * sPolarized) + (rPolarized * rPolarized));
Ray refractedRay = Ray(hit.point, n1divn2 * rayDirection + hit.normal * (n1divn2 * rayDdotN - sqrtf(k)));
return Fr * Reflect(rayDirection, hit, bounces - 1) + (1 - Fr) * GetPixelColor(refractedRay, bounces - 1);
}
}
default:
break;
}
}
// Background gradient
float t = 0.5f * (ray.GetDirection().x + 2);
return (1.0f - t) * color(1, 1, 1) + t * color(0.45f, 0.45f, 1.0f);
}