ShirleyTracer is an archived C++ path tracer built while working through Peter Shirley, Trevor David Black, and Steve Hollasch’s Ray Tracing in One Weekend series.
It was my first substantial offline-rendering project after earlier work in real-time OpenGL rasterisation. The goal was not to design a production renderer, but to implement the sequence of ideas in the books directly enough that I could understand the mechanics of ray generation, scattering, recursive light transport, texture lookup, acceleration, volumetric media, and importance sampling from the ground up.
The main branch now contains the completed book-three implementation. Earlier branches are preserved as checkpoints through the series.
This repository records an early stage of my graphics-programming path. It is useful as evidence of the rendering concepts I implemented and studied, but the C++ structure is not representative of my current engineering standards.
My current renderer work continues in Indus, a multithreaded C++23 CPU path tracer with a more deliberate renderer architecture, BSDF system, SAH BVH acceleration, progressive preview, concurrent scheduling, and runtime instrumentation.
Gallery

At a glance
std::thread.What I implemented
Ray tracing core
- Ray, vector, point, colour, and interval primitives.
- Recursive radiance evaluation with configurable maximum depth.
- Per-pixel stochastic sampling for anti-aliasing.
- Gamma-corrected colour output.
- Scene traversal through a common hittable/world-object interface.
- Hit records carrying intersection point, surface normal, material, texture coordinates, and front-face orientation.
Camera and image generation
- Configurable image dimensions, samples per pixel, and maximum bounce depth.
- Camera placement through look-from, look-at, up-vector, field-of-view, and focus-distance controls.
- Thin-lens defocus blur through disk sampling.
- Motion blur through time-sampled rays and moving objects.
- PPM image output with ImageMagick conversion to PNG.
- Optional multithreaded rendering by splitting image rows across hardware threads.
Materials and scattering
- Lambertian diffuse scattering with cosine-weighted behaviour.
- Fuzzy metallic reflection.
- Dielectric reflection/refraction with Schlick-style Fresnel approximation.
- Diffuse emissive materials for light-emitting geometry.
- Isotropic scattering for constant-density participating media.
- Scatter records that separate attenuation, emitted radiance, specular paths, and PDF-driven scattering.
Geometry and acceleration
- Sphere geometry, including static and moving spheres.
- Quad geometry used for Cornell-box style scenes and area lights.
- Translation and Y-axis rotation wrappers for scene objects.
- Axis-aligned bounding boxes for objects and object collections.
- BVH construction over hittable objects to reduce intersection cost.
Textures and procedural detail
- Constant-colour textures.
- Checker textures.
- Image-backed textures using
stb_image. - Perlin noise with shuffled permutation tables.
- Turbulence-style procedural noise used for marble-like surfaces.
Direct lighting and importance sampling
- Explicit light-object lists passed into the camera render path.
- Probability-density interfaces for direction sampling.
- Cosine hemisphere PDFs for diffuse scattering.
- Object PDFs for sampling directions towards hittable light geometry.
- Sphere PDFs and mixed PDFs.
- Mixture sampling between material scattering and light sampling to reduce noise in direct-light scenes.
Volumes
- Constant-density medium wrapper around boundary geometry.
- Exponential-distance sampling through media.
- Isotropic scattering material for smoke/fog-like effects.
- Cornell-box style experimentation with volumetric objects.
Rendering flow
At a high level, the completed implementation renders each frame like this:
1Build scene and light list
2 |
3 v
4Configure camera and sampling parameters
5 |
6 v
7Split image into row ranges for worker threads
8 |
9 v
10For each pixel sample:
11 generate camera ray with lens/time samples
12 |
13 v
14Trace ray through world/BVH
15 |
16 +--> miss: return background radiance
17 |
18 +--> hit emissive surface: accumulate emitted radiance
19 |
20 +--> hit scattering surface/medium:
21 sample material and/or light PDF
22 update attenuation and recurse
23 |
24 v
25Average samples, gamma correct, write image
26 |
27 v
28Convert PPM output to PNG through ImageMagick
Source layout
The project is primarily header-driven and organised around small renderer components:
1src/
2 main.cpp Scene selection and executable entry point
3 dep/stb_image.h Third-party image loader
4 headers/base/ Ray, vector, camera, material, texture, PDF, BVH, AABB, utility code
5 headers/materials/ Lambertian, metal, dielectric, emissive, and isotropic materials
6 headers/textures/ Solid colour, checker, image, and noise textures
7 headers/world_objects/ Spheres, quads, volumes, transforms, and object collections
Building
The project was developed on Windows with Visual Studio.
Requirements
- Visual Studio with C++ desktop-development support.
- C++20-capable MSVC toolchain for the current code style and standard library use.
- ImageMagick available on
PATHif you want automatic PPM-to-PNG conversion through the existingmagick convert image.ppm render.pngcall.
The repository includes the Visual Studio solution and project files used during development.
Visual Studio
- Clone the repository.
- Open
WeekendRT.sln. - Select an
x64configuration. - Build and run the executable.
The active scene is selected in src/main.cpp by choosing which render function is called.
Project context
This was the project that gave me my first working mental model of offline rendering. It made the basic path-tracing loop concrete: camera rays, intersections, material scattering, emitted light, random sampling, recursive radiance estimates, and image accumulation.
It also exposed the limits of simply following a tutorial architecture. By the end of the third book I had implemented many important rendering features, but I also understood that I needed stronger foundations in modern C++, numerical robustness, sampling theory, acceleration structures, and renderer design. That gap is what eventually led me to build Indus as a more independent renderer project.
Status
This repository is archived and not under active development.
It is retained as a record of my first complete path-tracing study project and as a milestone between my earlier OpenGL work and my current physically based rendering work in Indus.
References and third-party software
Primary reference:
- Peter Shirley, Trevor David Black, and Steve Hollasch, Ray Tracing in One Weekend series.
Third-party software:
- Sean Barrett’s
stb_imagefor image texture loading. - ImageMagick for converting generated PPM images to PNG.
