Ray Tracer

Overview

A CPU-based ray tracer built from scratch in C++ that renders 3D scenes with physically accurate lighting, shadows, and reflections. Every part of the pipeline was implemented by hand - from ray generation and geometry intersection to Phong shading and recursive reflections - with no reliance on existing rendering engines or graphics frameworks.

The renderer was built incrementally so the visual contribution of each feature could be isolated and compared directly, which is what the viewer above demonstrates.

Full source code on GitHub, with separate branches for antialiasing and recursive reflections.

renderer progression

Ray Tracer Viewer

Snow · Stage 1 of 5


What Is a Ray Tracer?

Think about how you see the world. Light travels from a source, bounces off objects, and eventually reaches your eye. A ray tracer reverses that process. Instead of simulating light going outward from a source, it starts at the camera and works backwards, firing one ray per pixel into the scene and asking: what does this pixel see, and how is it lit?

Backwards ray tracing diagram showing rays fired from camera through pixels into the scene
Backwards ray tracing — rays originate at the camera and travel through each pixel into the scene. Source: Wikipedia, CC BY-SA 3.0

Most real-time graphics use a faster technique called rasterization instead. While rasterization is great for speed, it struggles to simulate how light actually behaves. Shadows, reflections, and the way light bounces between surfaces all have to be faked using clever tricks. Ray tracing does not need those tricks - shadows fall naturally because a blocked ray means no light, and reflections work because a ray can bounce and pick up color from whatever it hits next.

Sources: NVIDIA Blog, Wikipedia, Scratchapixel

Core Features

Ray Generation

For every pixel in a 640x480 image, a ray is fired from the camera into the scene. The direction of each ray is computed from the field of view and aspect ratio, mapping screen coordinates into 3D camera space.

Geometry Intersection

Two primitive types are supported. Spheres use a quadratic intersection formula, solving for where the ray meets the sphere surface. Triangles use a plane intersection followed by a barycentric coordinate test to confirm the hit lands inside the triangle boundary. The same barycentric weights are reused later for smooth shading.

Phong Illumination

Lighting is computed per hit point using the Phong model, combining an ambient base, a diffuse term that responds to the angle between the surface and light, and a specular highlight that sharpens on glossy materials. Triangle surfaces interpolate normals and material properties across the surface using barycentric coordinates, giving smooth gradients instead of flat facets.

Shadow Rays

After every surface hit, a secondary ray is fired toward each light source. If any geometry blocks the path, that light is excluded from the final color. Scenes with multiple lights produce partial shadows correctly.

Extensions

Two extra features were implemented in separate branches. Antialiasing fires a 2x2 grid of rays per pixel and averages the result, smoothing jagged silhouette edges. Recursive reflections bounce rays off surfaces up to a configurable depth, blending reflected scene color with local Phong shading weighted by the surface's specular value.


Applications and Tradeoffs

Ray tracing produces physically accurate images by simulating how light actually behaves. Here is how it compares to rasterization, the technique used in most real-time applications:

Ray TracingRasterization
ShadowsNatural, no tricks neededApproximated via shadow maps
ReflectionsAccurate, recursiveFaked with cubemaps or screen-space tricks
Light bouncingPhysically correctNot supported without extra passes
SpeedSlow, expensive per pixelFast, optimized for GPUs
Primary useFilm, VFX, product renderingGames, real-time applications

Where it gets used today

Ray tracing is now finding its way into real-time pipelines. Games like Cyberpunk 2077 and Alan Wake 2 use ray tracing selectively for shadows and reflections while rasterizing everything else. The tradeoff is still real - enabling full ray tracing tanks frame rates even on high-end hardware.

Building this renderer made those tradeoffs tangible. Every feature added - shadow rays, reflection recursion, antialiasing - had a direct and measurable impact on render time. That hands-on understanding of where the cost comes from is something you do not get from using an engine.


Source Code