SkillAgentSearch skills...

PSRayTracing

A (modern) C++ implementation of the Peter Shirley Ray Tracing mini-books (https://raytracing.github.io). Features a clean project structure, perf. improvements (compared to the original code), multi-core rendering, and more.

Install / Use

/learn @define-private-public/PSRayTracing
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

######################################### Peter Shirley Ray Tracing (in modern C++) #########################################

|book2_final_render|

The official place where I do most of the work for this is over on GitLab <https://gitlab.com/define-private-public/PSRayTracing>_ Though I do field questions on the GitHub mirror <https://github.com/define-private-public/PSRayTracing/>_ To contact me, you can always @ me on Twitter as @DefPriPub <https://twitter.com/DefPriPub>_ (Or my personal website <https://16bpp.net/>_)

Now with an Android, iOS, and macOS (Apple Silicon) GUI:

|PSRayTracingGooglePlay|_ |PSRayTracingAppleAppStore|_

(It also runs on Windows, Mac (Intel), Linux,, but you need to build that for yourself in the meantime.)

.. contents ::


What Is This?


This repo is an implementation of Peter Shirley's Ray Tracing mini-books_, done in modern C++ (17), with a different project layout and all sorts of performance boosts. The CMake build script allows the user to toggle on/off most of the changes made from the reference implementation; as to better see the effects of these changes.

Compared to the book's code, mine is able to render the final scene in about 1/4 of the time. Without radically changing the architecture of the renderer and using (near) vanilla C++.

There are other fun features such as multi-core rendering, configurable render parameters (e.g. samples per pixel, max ray depth), and progress bars; it's the little things that count. It should be able to replicate all of the scenes from all three books.

What I like about how this book is structured is that it shows you how to make incremental changes to the ray tracer. With these step-by-step changes in book 3 though, it was getting very difficult to have my code reproduce every step, due to many structural changes in critical sections. Originally the code for book 3 was off in its own separate branch (called book3), but it has now been mereged into the mainline branch (that is master). The PDFVariant optimization has also come along with it (and is now a CMake configuration variable instead of a second separate branch). Note that getting book 3's code to work alongside that of books 1 & 2 did required adjusting some of the architecture a bit; but not my too much.

I've decided to license this implementation under the Apache License (2.0). The full text is in the file LICENSE.txt. The only exception to this is src/third_party, as those are externally provided projects. Check those files for their licenses. Note that the books (and the book code) is under CC0 1.0 Universal. If you end up using any of this, a shout out would be appreciated (and telling me too).


Why?


I first went through the books back in mid 2016 when they were new. That time I did it though as an exercise to learn Nim_ It's kind of cool to see how much these books have blown up in popularity. Ray Tracing seems to be quite in vogue recently, and I was looking for a project to learn modern C++ and better project architecture. This was also an experiment to see how far I could push a CPU render and optimize my code while keeping things simple, portable, and reproducible.


Some Blog Posts


Care to read a little more about this project? Check out these:

  • Making the first few revisions of the project <https://16bpp.net/blog/post/psraytracing-a-revisit-of-the-peter-shirley-minibooks-4-years-later/>_

  • Using Python to do automated testing & performance measuring <https://16bpp.net/blog/post/automated-testing-of-a-ray-tracer/>_

  • Adding a Qt/QML UI that works seamlessly on Mobile & Desktop <https://16bpp.net/blog/post/making-a-cross-platform-mobile-desktop-app-with-qt-62/>_

  • Localizing the GUI app into Japanese (日本語)and German (Deutsch) <https://16bpp.net/blog/post/localizing-a-qt-app-or-anything-else-for-that-matter/>_

    • This one is more about localizing Qt apps & software localization in general; not so much ray tracing
  • Measuring the impact of the final keyword <https://16bpp.net/blog/post/the-performance-impact-of-cpp-final-keyword/>_

  • Finding out when noexcept helps performance (and when it doesn't) <https://16bpp.net/blog/post/noexcept-can-sometimes-help-or-hurt-performance/>_

  • Interview on CppCast episode 389 about this project <https://cppcast.com/benchmarking_language_keywords/>_

  • Investigating the Performance of random sampling methods <https://16bpp.net/blog/post/when-greedy-algorithms-can-be-faster/>_

  • Finding a faster (and better) approximation for arcsine <https://16bpp.net/blog/post/faster-asin-was-hiding-in-plain-sight/>_

    • And then making it even quicker <https://16bpp.net/blog/post/even-faster-asin-was-staring-right-at-me/>_

Building and Basic Usage


I initially developed this on an Ubuntu 18.04 machine using GCC 10.x; but now its moved to newer versions of Ubuntu (22.04 LTS) and GCC (11 & 12). It runs on Windows 10/11 via MSYS2 (also GCC). It also compiles via clang 11+ without a hitch. macOS & xcode/clang have also been testing and verified. Something I could use help with is getting a build working with MSVC on Windows.

==================================== Qt/QML based UI for Mobile & Desktop

Don't want to use the command line interface? Want to see how this performs on your phone, tablet, or chromebook? Take a look at the qt_ui/ subfolder. Be sure the check the README.rst over there for some more instructions.

============ Requirements

  • A C++17 compiler. I'd recommend GCC 11/12 (or higher)

  • CMake 3.x. Using a CMake GUI application (such as ccmake) will make your life easier if you want to toggle on/off changes from the reference implementation

============ How To Build

  1. In the root of this project, make a build directory and go into it: mkdir build && cd build/

  2. Set your desired compiler (e.g. export CC=gcc-12, export CXX=g++-12)

  3. Run CMake w/ build type set to be a release: cmake ../ -DCMAKE_BUILD_TYPE=Release

  4. Build it: make


How To Use


If you ever get lost, doing a simple ./PSRayTracing --help should give you a list of all the options available, as well as their defaults. Here are some of the more important ones:

  • --scene <scene_id_string>, scene from book(s) to render (default is book2::final_scene).

  • -n <integer>, number of samples per pixel (default is 25)

  • -j <integer>, how many cores/threads to render with (default is 1)

  • -s <integer>x<integer>, resolution of the render (default is 960x540)

  • -o <filename>.png, file to save the render to (default is render.png). Note that this will always overwrite any existing file.

If you want to see what scenes are available to render, supply --list-scenes as an argument and it should show you all that are implemented. They should be in order as they were presented in the book.

So for example, If you do ./PSRayTracing by itself, it will render Book 2's final scene, with 25 samples per pixel, on a single core, saving it to render.png with a resolution of 540p. Though if you do ./PSRayTracing -n 250 -j 4 -s 1920x1080 --scene book1::normal_sphere, you'll get that sphere using it's surface normal (to shade it), with 250 samples/pixel, rendering on four cores at 1080p; also saving to render.png.

You should be good now to start rendering.

If you want to see what scenes, supply the flag --list-scenes to the executable. The output form this is different depending upong what branch you're currently on.


What's Different?


Oh, quite a bit. This isn't an exhaustive list though. (I forgot to document some stuff along the way, my bad ¯\( ツ ))

This project was started around September 2020, which is based off of v3.2.0 of the original book code. There have been a few changes since then (e.g. v4.x.x is out now). So some code has diverged but is mostly the same.

======================== Structural/Architectural

  1. Naming changes; e.g. I did things like BVHNode instead of bvh_node. These are just preferences of mine

  2. Classes like material have become strict abstract base classes, IMaterial for instance; take a look at src/Interfaces/ to see more

  3. Instead of rendering to PPM files (via standard output), stb_image_write is used to write directly to PNGs; A file format that you're not ashamed to take back home and introduce to Mom.

  4. The random_* functions have put into their own RandomGenerator object; this helps perf. and multi-threading (more further down).

  5. More files/structs/classes and compartmentalization of functionality. Imma neat freak

  6. A lot more const and const ref parameters, these help perf. and create cleaner, more predictable code

  7. More/less inline functions

    • Sometimes inlining makes sense and can boost perf well (e.g. Vec3). For virtual functions (.e.g IMaterial, IHittable, etc), it does jack
  8. Using Vec3 as a Point

    • Yeah yeah, I can hear one of my CG professors from college saying “A point is not a vector, a vector is not a point. You can't add or multiply two points.” But I wanted to keep things easy here. Vec3, 3D points, and colors are used quite interchangeably in this code
  9. Vec3 is also not backed by an array of three elements. We have a hard x, a hard y, and a hard z. Saved me typing parenthesis

  10. The Box type also requires you to pass in an RNG to it's constructor. More on why in the perf. section

  11. Avoiding defining our own Deconstructors and copy/move/assignment constructors.

    • Modern compilers are really

Related Skills

View on GitHub
GitHub Stars302
CategoryDevelopment
Updated11d ago
Forks12

Languages

Jupyter Notebook

Security Score

100/100

Audited on Mar 19, 2026

No findings