MARKO SOBAK

Math PhD · Embedded C/C++ developer

Open to C/C++ roles

Vienna, AT

← back

Coding project

Spacetime Raytracer

Real-time C++ relativistic raytracer running at 60 fps at 800×800 on the CPU, built on a templated tensor math library and an adaptive Runge-Kutta solver written from scratch.

stackC++20numerical solversImGuiCMake
repomsobak/SpacetimeRaytracer

Overview

Real-time simulation of light-bending around black holes or wormholes, with relativity-accurate movements of the spaceship. Camera rotations are modelled using quaternions.

Technical highlights

Implementation

General

The project is built using the CMake build system. All of the third-party dependencies are fetched automatically at the CMake configuration step. High resolution textures that can be used in the simulation are also automatically downloaded provided that the FETCH_TEXTURES flag is set. For the release build, the -ffast-math flag is enabled (visual inspection with and without the flag showed no visible loss of accuracy; the same is true for using double-precision types rather than single-precision).

Structure

The project almost entirely consists of header-only modules, with a single main.cpp file that constructs the App and runs it. The modules are Image, Math, Physics, GUI, CLI, each wrapped in its own namespace.

Raytracing optimization

Each frame of the simulation is generated pixel-by-pixel. For each pixel, the direction of the incoming light ray is determined based on the projection used for the camera. The light ray is then traced backwards to its “origin” by integrating (using an adaptive RKF45 scheme) the geodesic equation for the selected spacetime, which in particular describes how light bends due to the curvature of spacetime.

Note that the origin of the light ray is either:

The color of the pixel is then determined by mapping the origin of the light ray to the selected texture for the universe/body.

A naive per-pixel geodesic solve runs too slowly on the CPU, even when parallelized. Profiling with perf revealed that the CPU time is mainly dominated by floating-point operations, so the main goal is to reduce them. Two details are key for achieving this: