Rendering a black hole

Recap

The distorsion of light around a black hole was made famous by Interstellar and the recent direct images of M87* and Sgr A* ; however, physically accurate rendering would have required complex computations of general relativity, preventing an easy realtime rendering (for video games, visualisation or others).

For the 2022 computer graphics course at the MPRI, I created a project in GLSL (C++ interface to OpenGL) with Orphée Radet in order to render a black hole in real time. It consists of a pixel shader implementing a modified version of ray tracing, bending the rays according to general relativity.

However, GR computations do not have explicit solutions, even for the most simple metric, the Schwarzschild metric. We approximate the bended ray with two straight lines connecting near the periapsis of the light ray's orbit, the angle between them being given by GR ; this produces few artifacts, mainly very close to the black hole.

Detailed

Black hole are magnificent and mysterious objects; they are are some of the most extreme environments in our universe. A mass singularity at the center is so dense, it captures light rays passing nearer than a certain distance; this distance is called the Schwarzschild radius of the black hole and is the radius of the black circle we see from the outside. Further than that, light rays are still deviated; near the fatal radius, they can even circle multiple times around the black hole.

To obtain this, we wrote a pixel shader: for each pixel in the screen, it should give the appropriate color to render on the screen. For each pixel, we throw a light ray and see if it collides with an object, with the black hole or if it goes to infinity, colliding with the skybox. However, instead of a being straight, the ray should be deviated by the black hole! We represent this by two straight lines, which is a simplification of the real trajectory. Indeed, even in the simplest physical case (a point mass, implying spherical symmetry: the so called Schwarzschild metric), the real trajectory (called a geodesic) does not have an analytical (explicit) form; thus, we would have to proceed tiny step by tiny step, for each ray. There are other, nicer ways to bypass this problem of course, but we went with a simple solution, allowing quick implementation and testing.

The results exceeded our expectations: the simulation runned smoothly at 60 fps on our laptops, which had integrated GPUs (thus not very good ones) ; you can see here a capture of the resulting rendering. The scene only contains the black hole code, a skybox (images at "infinity"), and an accretion disc (hot gas orbiting the black hole, and falling in it) here represented by a planar annulus with appropriate Perlin noise to give the "hot gas" aspect and motion. The ray tracing approximation only gave a few artifacts (sometimes visible in the inner radius of the accretion disc), and gives an overall very satisfying aspect to the black hole.

Our code isn't production ready at the moment: everything is hard coded in a single file, with a ShaderToy-like syntax, as modularity wasn't an objective in the first part of the project. If I find the time, I will clean up the code and make it available on Github to allow others to reuse and expand it. Do not hesitate to contact me about the project, for questions, inquiries or others!