Ray Tracing 001: Introduction


Introduction

This section is dedicated to my learning journey on how to build a ray tracer. Each post in this series will document one step in this journey.

I will begin with Peter Shirley’s excellent book Ray Tracing in a Weekend and his following two volumes Ray Tracing - The Next Week and Ray Tracing - The Rest of Your Life. I found the first book on Amazon Kindle some time ago, but it’s now available for free at raytracing.github.io.

But this will not be limited to these books alone. I plan to explore multi-threaded and parallel techniques, as well as more advanced topics with further papers, articles, tutorials and literature including the Ray Tracing Gems.

Further down in my timeline I want to produce some animations as well: First, a ray-traced animation of the Triadic Ballet in time for the 100th anniversary of its premiere in September 2022, then explore the realm of physics-based animation and fluid simulations. But let’s start with a single simple image first. :)

I tested and built the code with the GNU compiler on Linux Mint and Windows+cygwin as well as Microsoft C++ with Visual Studio Code on Windows. It should work on other platforms as well, but let me know if something does not work.

I also want to look into and learn more about cmake, jenkins and other tools used in the real world, but this will have to wait until it makes sense for this project. At this time I want to focus on graphics programming.

In the last 20+ years (crazy, I never realized it’s been that long) I’ve mostly been involved with web development, database, ecommerce- and marketing-support applications and the like. None of the fun stuff, no computer graphics, animation, mathematics, physics, nothing scientific or academic, flashy or artistic.

I have to admit that some topics have been and still are a little difficult to grasp. Sometimes I have to step back for a refresher or learning a prerequisite to fill a knowledge gap before I can resume my original project. I will include these excursions as well in case someone is in a similar situation and needs a refresher in C++ or math.

To bridge the gap between web and graphics programming, I will also include a Javascript version in my source code. I’d like to add some interactive web-applets, but I’m also interested to see how it will compare to C++. I’m sure the scenes will soon become too complex and time-consuming to run in a browser, especially in the beginning without any optimizations, but let’s see how far I can take this and what I can do to improve performance.

Recently I’ve also added a WebAssembly version with Emscripten to my source code. I added just a few lines of code and compiler directives for Emscripten based on some SDL tutorials I found. I’m new to WebAssembly and Emscripten, and I’m sure there are better ways to do it. But the code compiles and produces web-friendly results that actually perform quite a bit better than pure Javascript. I’ll probably explore WebAssembly once I’ve completed the basics. If you find the first chapters laughably simple and buggy, I hope you will notice an improvement in the later chapters. :) That’s part of the learning journey.

The complete code is available on GitHub here: github.com/celeph/ray-tracing.

For the original source code (the correct “master solution” so to speak) of the first chapters, please visit Peter Shirley’s book repository.

And one more thing - I plan to summarize in my own words what a chapter is about and what I’ve learned. I may add some extras, drawings, applets, more verbose math, C++ and my own experiments not found in the original book, but I don’t want to just repeat the book or paper of the original author(s).

They have done all the work already, and it would be a waste of time to just copy it all. I’ll refer to the original sources for more details and expert insights at the bottom of each chapter.

There’s always a chance I understood something wrong, made a mistake, or didn’t follow best practices or proper style. If you spot anything that’s wrong or could use some improvement, please let me know. Any feedback, suggestions, or bug reports are always appreciated!

Now let’s get started, and enjoy!

Gerrit

Simple Image with PPM

The Portable PixMap (PPM) is a simple text-based image format. No special libraries needed: create an image by simply writing pixel data to a text file.

// ppm-example.cpp
#include <iostream>

int main() {
  int nx = 200;
  int ny = 100;

  std::cout << "P3\n" << nx << " " << ny << "\n255\n";
  for (int j = ny-1; j >= 0; j--) {
    for (int i = 0; i < nx; i++) {
      float r = float(i) / float(nx); // left to right from 0 to 0.995
      float g = float(j) / float(ny); // top to bottom from 0.99 to 0
      float b = 0.2;

      int ir = int(255.99 * r); // left to right from 0 to 254
      int ig = int(255.99 * g); // top to bottom from 253 to 0
      int ib = int(255.99 * b); // always 51

      std::cout << ir << " " << ig << " " << ib << "\n";
    }
  }
}

Simple Image with Javascript and Canvas

The Javascript code below is almost identical with the C++ code but instead of a PPM file stream it renders each pixel in a 200x100 canvas element.

To keep the color gradient in the same direction as the PPM I reversed the y-direction in the fillRect() call.

Credits and Further Reading

Next Steps