Ray-Tracing Black Holes
Rendering Schwarzschild and Kerr black holes from the metric up — shadow, lensing, and a Doppler-boosted disk.
The idea
This was my final project for PHYS 161 (Black Holes) with Prof. George Fuller. The goal was to take the general relativity we'd been doing on paper — metrics, Christoffel symbols, the geodesic equation — and turn it into actual images of a black hole: the shadow, an accretion disk, and a distorted background sky.
I built a small ray tracer from scratch for two spacetimes — the non-spinning Schwarzschild black hole and the spinning Kerr black hole — so I could see directly how spin, frame dragging, and relativistic Doppler shifts change what a black hole looks like. The north star was Interstellar (2014): I wanted those visuals, but coming out of my own code, from the equations up.
How it works — a four-box pipeline
- Pick a spacetime, build the metric. Implement gμν(r,θ). For Schwarzschild I hard-code the analytic Christoffel symbols; for Kerr I take finite-difference derivatives of the metric to build them approximately.
- Fire a photon per pixel. Place a camera at radius R, build a local orthonormal tetrad, and for each pixel construct an initial photon four-momentum in the camera frame, then transform it into coordinates.
- Integrate the null geodesic. Solve the geodesic equation as a first-order system — first with a hand-written Euler step, then upgraded to RK45 (SciPy's solve_ivp) for accuracy — watching for three fates: it falls through the horizon (radius 2M for Schwarzschild, M + √(M² − a²) for Kerr), it hits the disk, or it escapes to the sky.
- Color the pixel. Horizon hits are black; disk hits get a base color scaled by the Doppler factor; escaping rays are mapped onto a rainbow test-sphere or the Milky Way sky by their final direction.
The two spacetimes are just two metrics feeding the same machine. Schwarzschild, in the usual coordinates:
Kerr adds the spin a — and with it a cross term dt dφ that mixes time and rotation. That single term is frame dragging:
Light follows null geodesics — paths with gμν kᵘ kᵛ = 0 — and to color the disk I compute a relativistic redshift/Doppler factor from the four-velocities of the gas and the observer:
Results
To make the lensing obvious, I first rendered the black holes against a rainbow-striped sphere. The difference between no spin and spin is immediate:


Sweeping the Kerr spin parameter a from zero upward, you can watch the shadow deform and drift:



The same sweep against a vertical rainbow bends the stripes the other way, but tells the identical story — symmetric with no spin, drifting and lopsided as the spin grows:



Swap the rainbow for a real Milky Way sky and add the Doppler-boosted disk, and it starts to look like the real thing:
What I took from it
Working directly with the metric, the Christoffel symbols, and the geodesic equation is what finally connected the math of general relativity to something I could see. Changing from Schwarzschild to Kerr visibly changes the light paths — and therefore the shape and position of the shadow. Building the Doppler factor out of four-velocities made relativistic beaming concrete, because I could watch one side of the disk brighten and the other fade. Understanding a system until I feel part of it — this is what that means for me.
Read the full write-up (PDF) →