The Ray Tracer Challenge
6 Jan 2026
Tags: ocaml, graphics, testing
For the last few years I've spent the run up to the festive break working on something graphical, and this year whilst I was a little late to start, I decided to have a go at the Ray Tracer Challenge book by Jamis Buck. This book provides a language-neutral guide to building a classic old-school ray tracer, an art-form that scratches the nostalgic itch for me, as I have vague memories of trying to use POV-ray back in the early 90s at uni, back before even Pixar was using the technique to make films.
The book builds you up from first principles, first gently introducing you to the maths needed, though without explaining why, just how, to keep things moving implementation wise (it provides links to articles on the how for you to chase in your own time). The first couple of chapters you don't get any pretty pictures out, but it is here that the book does a wonderful trick: it makes you write unit tests for every tiny step. Make a tuple to hold a point: write a test or two, change it to also hold a vector, write another unit test. Now add matrices, and we have a few more tests, then multiply matrices and add tests for those. Whilst this might sound like drudge work to some, it actually means you get little sense of achievement on every page when you get some tests to pass, rather than making you wait until you're several chapters in and you make your first scene:
I actually jazzed this up, as the book just has you do a flat projection of a sphere, but I thought it was more interesting to make a depth map from it to convince myself we had 3D objects early on.
However, once the first few chapters of building up the fundamentals are out the way, you start to progress at a reasonable clip - though still adding tests at every step. It wasn't long before we added lighting using Phong shading, which is a simple model that looks reasonably good quickly, and for me has a very nostalgic look and feel to it.
I chose to do the challenge in OCaml, which is a language I enjoy using, but haven't had much call to use this last year outside of hobby things like Claudius. On one hand, this meant I was using a language I was familiar with, but it also is one goes slightly contrary to the methods the book takes, which forced me to make some fun design decisions on how to translate things when it uses polymorphic types for different shape types or patterns. Nothing earth shattering, but in the past I've not needed to make those decisions, so it was good practice to take programming patterns I'm familiar with in imperative languages and be forced to find the idiomatic way to tackle it in OCaml.
Above you can see we start to add multiple objects and have a way to specify their location. This is where my experience doing things like Tiny Code Christmas and Genuary paid off, as generating patters and colours with a few well placed trig functions is somewhat second nature to me now :)
To render the graphics out I'm actually using TSDL, and OCaml wrapper for the multi-platform SDL graphics library. Thankfully I was able to crib from my work on Claudius to get this up and running, as otherwise the one slight let down to the book is that it has you generate your output in the somewhat obscure PBM format, which is a text file based image format. Preview on the mac will apparently display these files, but otherwise you need to find a tool to convert them. Given the book specifies no language for you to use, there isn't much it can do here I guess, but it is the one rough point in the proceedings.
My SDL based output viewer was good as it also let me "animate" the output, with the lighting source actually rotating around the scene, albeit slowly as each frame takes ten seconds to draw currently in its unoptimised state. Still, when you start to add shadows, that sort of "animation" really helps bring the scenes alive a little.
Even at the later chapters, where we're adding shadows, or when we introduce an infinite plane over which to float your objects like we have below, you're still adding unit tests for every little step. This means that with just one exception I think every time I went to render something to the screen, it just worked. Which is just as well, as there's a lot of places it can go wrong as you get to the later stages.
But it's here that I think the test drive approach really helps: you never really feel swamped by the complexity of ray tracing. Because as the reader you're going one unit test at a time, every step feels quite small. It reminds me of the book Code by Charles Petzold, which I read over twenty years ago now, which pulls a similar trick. It walks you through how a computer works starting with just a simple relay switch, which then it uses to build a logic element, then a gate, then an adder, etc. etc. until you arrive a few hundred pages later at a full working CPU that is based entirely on relays. But because each increment is build on the previous one with no reference to the broader context, you're elegantly guided through something increadibly complex without being made aware of that complexity until you get to the end and look back. Buck does a similar trick in this book.
The test driven approach also made it an excellent thing to work on over a festive period. Because each step was small and self contained within a unit test, it was easy to do ten minutes here and there and never feel you were leaving mental state that would need to be rebuilt. I could just chip away at it as time allowed. I only managed to get half the way through the book by the end of the festive break, but by the end I was starting to make some classic Ray Tracer images from my childhood with reflections and the ubiquitous grid texture. All achieved with just a few minutes here and there each day.
The main point of this is that the Ray Tracer Challenge book is by far and away the best introduction to Test Driven Development, and at no point does it state it is trying to do this, or try to convince you that unit testing is great. I just keeps saying "this way to pretty pictures!" and before you know it you have some nice graphics and just under 200 unit tests. It's really quite an amazing achievement.
So if you ever want a way to introduce a developer to the art of testing, this is a great first book for that. It also is a great book for making pretty pictures if you're into that sort of thing :)