Integrate timelike geodesics and Fermi-Walker tetrads in ingoing Kerr-Schild coordinates, sampled at a configurable proper-time cadence. Add movie-track-samples to preserve CSV events as frames. Document usage and singularity guards, and cover analytic orbits, transport convergence, sampling, and CSV rendering.
234 lines
11 KiB
Markdown
234 lines
11 KiB
Markdown
# GR 4D ray tracing
|
||
|
||
**English** | [简体中文](README.zh-CN.md)
|
||
|
||
An offline spacetime renderer focused on physical accuracy. The project aims
|
||
to turn time-dependent numerical-relativity simulations, including binary
|
||
black-hole mergers, into 4K movies by tracing light rays backward through the
|
||
four-dimensional spacetime.
|
||
|
||
[](assets/images/schwarzschild_galactic_center.png)
|
||
|
||
*The 2MASS Galactic-center star field seen through Schwarzschild spacetime,
|
||
from a camera at radius 100 M. Click the image for the full 4K render;
|
||
[rendering command below](#example-galactic-center-field-through-schwarzschild-spacetime).*
|
||
|
||
Stars are individual catalog point sources with direction, temperature, and
|
||
amplitude. The renderer maps them into the camera image, accounting for
|
||
multiple images, gravitational lensing magnification, and frequency shifts,
|
||
then accumulates their sub-pixel point-spread functions (PSFs) into an HDR
|
||
image. Movie cameras are described by worldline and tetrad tracks.
|
||
|
||
Single images support independent coordinate position and look direction,
|
||
coordinate velocity, and camera roll in both backends. For example,
|
||
`--observer-position 1.75 0 0 --observer-velocity -0.5 0 0 --look-ra-deg 0 --look-dec-deg 0`
|
||
specifies an inward-moving Schwarzschild camera looking outward from inside
|
||
the horizon. See [single-frame camera parameters and complete commands](usage.md#single-frame-camera).
|
||
|
||
## Current status
|
||
|
||
The current implementation supports analytic **Minkowski** and
|
||
**Schwarzschild** spacetimes, single images and observer-track image sequences,
|
||
adaptive lens meshes, and reusable lens-map files. It is written primarily in
|
||
C with OpenMP CPU parallelism; an optional HIP backend accelerates PSF
|
||
accumulation.
|
||
|
||
The [Nmesh](https://github.com/nmeshsource/nmesh) numerical-spacetime backend and BBH rendering are still planned.
|
||
The current scope is black-hole capture and distant stellar backgrounds;
|
||
local matter emission, accretion disks, and plasma are outside this stage.
|
||
See the [design document](nr_spacetime_movie_renderer_design.md) for the
|
||
architecture and development roadmap.
|
||
|
||
## Build
|
||
|
||
The default build requires a C11 compiler with OpenMP support, GNU Make, and
|
||
libpng development files. From the repository root:
|
||
|
||
```sh
|
||
make -j
|
||
```
|
||
|
||
This builds both `build/Release/minkowski_sky` and
|
||
`build/Release/schwarzschild_sky`. For individual backends, Debug builds,
|
||
optional HDR/FITS output, HIP support, and regression checks, see
|
||
[build.md](build.md).
|
||
|
||
## Prepare the stellar catalog
|
||
|
||
The renderer accepts **any stellar catalog converted to the supported CSV
|
||
format**: four columns containing ICRS right ascension and declination in
|
||
degrees, temperature in kelvin, and amplitude, in that order. Use
|
||
`--catalog PATH` to load a single CSV.
|
||
|
||
**2MASS is the recommended survey catalog**, with download and processing
|
||
scripts provided by this project. Instructions are in
|
||
[assets/2mass/README.md](assets/2mass/README.md).
|
||
The full download takes approximately **three to four days**, so **contact me
|
||
for a compressed archive first** if possible. Place the processed tile files
|
||
under `assets/2mass/processed/all_sky/` for the commands below.
|
||
|
||
The included [assets/sky_grid_5deg.csv](assets/sky_grid_5deg.csv) is a synthetic
|
||
stellar grid for geometry and regression tests. It can be used directly with
|
||
`--catalog assets/sky_grid_5deg.csv`, without downloading survey data; see the
|
||
[test-grid example below](#example-synthetic-test-grid-with-mesh-overlay).
|
||
|
||
## Rendering examples
|
||
|
||
The examples below illustrate a few choices of sky field, spacetime, and
|
||
camera settings. After building and preparing the catalog, adapt these
|
||
commands to your own field of view, observer position, and rendering settings.
|
||
See [usage.md](usage.md) for the available controls and workflows.
|
||
|
||
### Example: Summer Triangle in flat spacetime
|
||
|
||
This example renders a field around the Summer Triangle:
|
||
|
||
```sh
|
||
mkdir -p output/imgs
|
||
./build/Release/minkowski_sky \
|
||
--all-sky-catalog assets/2mass/processed/all_sky \
|
||
--look-ra-deg 296 --look-dec-deg 27 --fov-deg 72 \
|
||
--width 3840 --height 2160 --exposure 1e12 \
|
||
--output output/imgs/summer_triangle.png
|
||
```
|
||
|
||
[](assets/images/summer_triangle.png)
|
||
|
||
*4K reference image with exposure `1e12`. Click to view at full resolution.*
|
||
|
||
Angles are in degrees; `--fov-deg` is the horizontal field of view. Exposure
|
||
is an adjustable display multiplier. Use `--verbose` for progress during long
|
||
renders.
|
||
|
||
### Example: Galactic-center field through Schwarzschild spacetime
|
||
|
||
This example uses a camera at radius 100 M to render the lensed
|
||
Galactic-center field shown at the top of this page:
|
||
|
||
```sh
|
||
mkdir -p output/imgs
|
||
./build/Release/schwarzschild_sky \
|
||
--all-sky-catalog assets/2mass/processed/all_sky \
|
||
--width 3840 --height 2160 \
|
||
--look-ra-deg 262.5 --look-dec-deg -30 --fov-deg 45 \
|
||
--observer-radius 100 --exposure 1e13 \
|
||
--coarse-cell-pixels 16 --refine-max-level 4 --refine-jacobian-min 0.2 \
|
||
--psf-fwhm-pixels 2.7 --psf-moffat-beta 4.5 \
|
||
--psf-relative-tail 1e-8 --psf-min-y 0 --max-cache-psf-flux 1e8 \
|
||
--catalog-load-workers 4 \
|
||
--output output/imgs/schwarzschild_galactic_center.png
|
||
```
|
||
|
||
This uses the reference image's rendering settings, including its
|
||
`--max-cache-psf-flux 1e8` preview approximation, which clips bright PSF wings
|
||
to the cache radius. The [original benchmark record](benchmarks/2mass_galactic_center_blackhole.md)
|
||
preserves the command and terminal output; the command above omits the optional
|
||
HDR export.
|
||
|
||
This example infers a position facing the hole from its look direction and radius. Adaptive refinement should
|
||
be configured for the desired image accuracy; it is disabled by default.
|
||
Camera controls, movie sequences, lens-map reuse, PSF settings, and HDR output
|
||
are described in [usage.md](usage.md). Both binaries provide a complete option
|
||
list with `--help`.
|
||
|
||
### Example: Looking outward just above the Schwarzschild horizon
|
||
|
||
This camera is static at `(2.1, 0, 0)` in Cartesian Kerr–Schild coordinates,
|
||
just outside the horizon at `r=2M` (`M=1`). RA=0°, Dec=0° points along +X,
|
||
radially outward. Its coordinate velocity is zero: this is a static
|
||
observer, not a freely falling one. The scene uses the bundled synthetic
|
||
stellar grid, so no survey download is needed.
|
||
|
||
```sh
|
||
mkdir -p output/imgs
|
||
./build/Release/schwarzschild_sky \
|
||
--catalog assets/sky_grid_5deg.csv \
|
||
--observer-position 2.1 0 0 \
|
||
--observer-velocity 0 0 0 \
|
||
--look-ra-deg 0 --look-dec-deg 0 \
|
||
--camera-roll-deg 0 \
|
||
--width 3840 --height 2160 --fov-deg 90 \
|
||
--coarse-cell-pixels 16 --refine-max-level 3 \
|
||
--exposure 0.01 \
|
||
--output output/imgs/schwarzschild_near_horizon_outward_R2.1_0.01_refine3.png
|
||
```
|
||
|
||
[](assets/images/schwarzschild_near_horizon_outward_R2.1_0.01_refine3.png)
|
||
|
||
*4K render with a 90° horizontal field of view, exposure `0.01`, and maximum
|
||
refinement level 3. Click to view at full resolution.*
|
||
|
||
The distant sky occupies a bounded angular region around the outward
|
||
direction, with repeated images crowded near its edge. Strong gravitational
|
||
blueshift pushes both the 3000 K and 12000 K test stars toward blue-white.
|
||
|
||
### Example: Synthetic test grid with mesh overlay
|
||
|
||
This example uses `assets/sky_grid_5deg.csv` to inspect lensing and adaptive
|
||
mesh refinement in Schwarzschild spacetime. `--draw-mesh` overlays the final
|
||
image-plane triangles.
|
||
|
||
```sh
|
||
mkdir -p output/imgs
|
||
./build/Release/schwarzschild_sky \
|
||
--max-cache-psf-flux 1e8 \
|
||
--catalog assets/sky_grid_5deg.csv \
|
||
--refine-max-level 3 --refine-jacobian-min 0.2 \
|
||
--width 3840 --height 2160 \
|
||
--look-ra-deg 0.1 --look-dec-deg 0.1 --fov-deg 45 \
|
||
--coarse-cell-pixels 32 \
|
||
--observer-radius 100 --exposure 0.2 \
|
||
--psf-fwhm-pixels 2.7 --psf-moffat-beta 4.5 --draw-mesh \
|
||
--output output/imgs/schwarzschild_test_grid.png
|
||
```
|
||
|
||
[](assets/images/schwarzschild_test_grid.png)
|
||
|
||
*4K test-grid reference image. Click to view at full resolution.*
|
||
|
||
### Freely falling Schwarzschild movie camera
|
||
|
||
`scripts/schwarzschild_camera_track.py` generates the canonical 21-column observer
|
||
CSV in ingoing Cartesian Kerr–Schild coordinates (`G=c=M=1`, matching the renderer).
|
||
It requires Python 3, NumPy and SciPy. Position is `(x,y,z)`; velocity is coordinate
|
||
`(dx/dt,dy/dt,dz/dt)`. Look RA/Dec and roll construct the initial rest-frame
|
||
forward/up/right legs with the same convention as the single-image camera. Without
|
||
look angles, the camera initially points toward the origin. The orientation then
|
||
follows Fermi–Walker transport; for free fall this is parallel transport, so it does
|
||
not keep pointing at the black hole. `--tetrad` alternatively accepts 16 row-major
|
||
components `(e0t,e0x,...,e3z)` of an orthonormal tetrad, with `e0` matching velocity.
|
||
|
||
```sh
|
||
python3 scripts/schwarzschild_camera_track.py \
|
||
--position 8 0 0 --velocity 0 0 0 \
|
||
--look-ra-deg 0 --look-dec-deg 0 --roll-deg 0 \
|
||
--fps 30 --duration 10 --output /tmp/freefall_camera.csv
|
||
make SPACETIME=schwarzschild all
|
||
mkdir -p output/freefall_frames
|
||
./build/Release/schwarzschild_sky \
|
||
--observer-track /tmp/freefall_camera.csv --movie-track-samples \
|
||
--frames-dir output/freefall_frames --catalog assets/sky_grid_5deg.csv \
|
||
--width 640 --height 360 --fov-deg 60 --exposure 0.2
|
||
ffmpeg -framerate 30 -i output/freefall_frames/frame_%06d.png \
|
||
-c:v libx264 -pix_fmt yuv420p output/freefall.mp4
|
||
```
|
||
|
||
Here `--duration` is elapsed **proper time**, and `--fps` is samples per unit proper
|
||
time. CSV rows occur at `tau=k/fps <= duration`, including the initial event and an
|
||
endpoint only if it lies on that cadence (10 at 30 fps gives 301 rows). `tau` starts
|
||
at zero; `--t0` sets the initial coordinate time. `--movie-track-samples` uses each
|
||
row exactly once and ignores renderer `--start-time`, `--duration`, and `--fps`;
|
||
encode the PNG sequence at the generator's fps. Without this flag the existing
|
||
movie mode resamples at uniform coordinate time, which changes the proper-time cadence.
|
||
|
||
DOP853 jointly integrates the geodesic and all tetrad legs using analytic metric
|
||
derivatives. Defaults: `--rtol 1e-10 --atol 1e-12 --stop-radius 0.001`.
|
||
Integration crosses the horizon and stops at this numerical guard before the
|
||
singularity, reporting its proper time and retaining only regular cadence samples.
|
||
The guard is not the exact singularity; reduce it and tolerances to check convergence.
|
||
The renderer's independent ray capture cutoff remains `r=1.5M`: rows inside it are
|
||
valid trajectory data but the current renderer captures those rays immediately.
|
||
The script reports maximum tetrad drift and rejects errors above `1e-6` rather
|
||
than silently repairing the transported frame. Run the orbit, transport and CSV
|
||
render regressions after building with `python3 tests/test_schwarzschild_camera_track.py`.
|