A physically based renderer for a rotating (Kerr) black hole and its volumetric accretion disk. Light is transported by integrating null geodesics through curved spacetime, so the lensing, the photon ring, and the relativistic Doppler and beaming effects all fall out of the physics rather than being faked in screen space.
It ships with a portable CPU backend (C++17, OpenMP) and an optional CUDA backend for NVIDIA GPUs. Both render the same scene from a single shared model.
The renderer is built up from a plain starfield to the final cinematic frame by
adding one physical effect at a time. Each image below is produced by
scripts/render_demo.sh, which simply re-runs the renderer with successive
features switched back on.
- Null-geodesic ray tracing through the Kerr metric with an RK4 integrator and adaptive stepping near the photon sphere.
- Volumetric accretion disk with a physically motivated temperature and density profile, procedural Perlin-Worley and ridged-multifractal detail, and Henyey-Greenstein multiple scattering.
- Relativistic optics: gravitational redshift, Doppler shift, and
g^4relativistic beaming. - Photon ring multi-order emission boost.
- HDR pipeline with adaptive anti-aliasing, bloom, diffraction spikes, and tone-mapped colour grading. Output to both PNG (8-bit) and EXR (HDR).
- Two interchangeable backends sharing one model: CPU (OpenMP) and CUDA.
Requires a C++17 compiler and zlib. OpenMP is on by default.
makeOn macOS, install the OpenMP runtime first (or build with make USE_OPENMP=0):
brew install libomp
makeRequires the CUDA toolkit with nvcc on PATH.
make USE_CUDA=1 # default arch sm_120 (Blackwell)
make USE_CUDA=1 CUDA_ARCH=sm_89 # Ada, e.g. RTX 4090
make USE_CUDA=1 CUDA_ARCH=native # auto-detect at compile timeThe binary is written to build/bin/singularity.
The renderer reads an equirectangular HDR starfield from
assets/skybox/skybox_8K.exr. That file is large and is not tracked in the
repository, so download one and place it there before rendering disk scenes.
(Step 1 of the demo is the skybox alone, so you can confirm it loads.)
The reference images here use NightSkyHDRI001 from ambientCG.
It is offered in several resolutions; download the EXR
you want and save it as assets/skybox/skybox_8K.exr.
To use a different file or resolution, either save it under that name or change
the hardcoded path in src/main.cpp:
skybox.load("assets/skybox/skybox_8K.exr"); // src/main.cpp:436Any equirectangular .exr works.
singularity [static|cinematic|snapshot] [720p|1080p|2k|4k] [flags]
Modes:
static— single-camera loop (default).cinematic— multi-keyframe camera arc over one full noise period.snapshot— a single frame att = 0(resolution argument applies here).
Every physical effect can be toggled off, which is exactly how the gallery above is generated:
| Flag | Effect |
|---|---|
--no-curvature |
Walk rays in straight lines (skip the RK4 geodesic integration) |
--no-disk |
Skip disk volumetric sampling |
--no-noise |
Smooth disk (no Perlin/Worley/ridge/temperature noise) |
--no-doppler |
g = 1, no frequency shift or beaming |
--no-scattering |
Drop the Henyey-Greenstein secondary rays |
--no-photon-ring |
Skip the photon-ring multi-order boost |
--no-aa |
Skip the adaptive-AA supersample pass |
--no-bloom |
Skip the Gaussian-pyramid bloom pass |
--no-diffraction |
Skip the diffraction-spike pass |
--no-grade |
Plain gamma 2.2 (skip the colour grade) |
--no-post |
Shorthand for --no-bloom --no-diffraction --no-grade |
--out NAME |
Override the output filename base |
Run singularity --help for the full list.
make # or: make USE_CUDA=1
scripts/render_demo.sh # writes the 8 stills to output/demo/build/bin/singularity cinematic
ffmpeg -framerate 24 -i output/cinematic/frame_%04d.png \
-c:v libx264 -preset slow -crf 16 -pix_fmt yuv420p \
-vf scale=1920:1080 output/cinematic.mp4The test suite uses doctest and covers the Kerr metric, the RK4 integrator, the ray marcher, anti-aliasing, the photon ring, Doppler shift, noise, scattering, and skybox sampling.
make testinclude/ Public headers
camera/ Camera model and trajectories
core/ Ray marcher, anti-aliasing
cuda/ CUDA device-side mirror of the core (.cuh)
physics/ Kerr metric, geodesic state, RK4
geometry/ Accretion disk
procedural/ Perlin / Worley noise
postprocess/ Bloom, diffraction, tone mapping, grade
volume/ Henyey-Greenstein phase function
utils/ Vectors, image I/O, skybox
src/ Implementations (mirrors include/)
cuda/ CUDA kernels
tests/ doctest unit tests
scripts/ render_demo.sh
external/ Vendored single-header libraries
- Valentin Best — @valentin-best
- Abdulkadir Kessaria — @KadirKess
Released under the MIT License.
Vendored third-party libraries (doctest, stb_image_write, tinyexr) retain their own licenses; see THIRD_PARTY.md.








