Most ray tracer tutorials go straight for C++ or even Python. I wanted to understand what was actually happening at the memory level — no classes, no smart pointers, no hidden constructors. Just structs, function pointers, and raw math.
The decision wasn't about masochism. It was about precision. When I read code in a high-level language, I'm always one abstraction removed from the actual computation. C strips that away. Every allocation is explicit. Every pointer is mine to manage. If something breaks, the blame is local.
The Geometry Problem
Writing a ray tracer forces you to think geometrically at every step. When you trace a ray and compute an intersection, there's no abstraction hiding the dot products and vector normalization. You feel every calculation. It's uncomfortable at first, then clarifying.
A ray is just an origin point and a direction vector. An intersection test for a sphere is just solving a quadratic equation. When you write it yourself — no glm::vec3, no Ray::intersect() — you remember it. The formula becomes yours.
typedef struct { float x, y, z; } Vec3;
float dot(Vec3 a, Vec3 b) {
return a.x*b.x + a.y*b.y + a.z*b.z;
}
int ray_sphere(Vec3 ro, Vec3 rd, Vec3 center, float r, float *t) {
Vec3 oc = { ro.x-center.x, ro.y-center.y, ro.z-center.z };
float a = dot(rd, rd);
float b = 2.0f * dot(oc, rd);
float c = dot(oc, oc) - r*r;
float disc = b*b - 4*a*c;
if (disc < 0) return 0;
*t = (-b - sqrtf(disc)) / (2.0f * a);
return 1;
}
The BVH Problem
The biggest lesson so far: the BVH (Bounding Volume Hierarchy) is where naive implementations die. Without it, your scene complexity is O(n) per ray. With it, it drops to O(log n). The difference between a 10-second render and a 100ms one is almost entirely this data structure.
Building it without a library means building the AABB intersection test by hand, the recursive tree split, and tuning the surface-area heuristic. It's tedious. It's also the only way I've ever truly understood a BVH. Reading about it and implementing it are entirely different experiences.
What I'd Tell Myself Before Starting
Start with spheres and a fixed camera. Get a pixel on screen. Don't think about BVH, materials, or lights until you can see a grey circle on a black background and know exactly why it's there. The rest follows naturally.
Also: floating point is your enemy and your only tool. Get comfortable with it early.