Doc: reorganize bilingual READMEs and build guide with reference renders
This commit is contained in:
1 parent
a18ebfbf1a
commit
94149d75e4
8 files changed
+612
-332
No files matched your search
@@ -1,360 +1,150 @@
|
|||||||
# GR 4D ray tracing — Phase 0 prototype
|
# GR 4D ray tracing
|
||||||
|
|
||||||
`minkowski_sky` is a deliberately small, CPU-only, single-frame Phase 0
|
**English** | [简体中文](README.zh-CN.md)
|
||||||
benchmark. It renders point sources from a sky catalog through an analytic
|
|
||||||
backend. It is not a sky texture: each source remains a direction, temperature,
|
|
||||||
and amplitude until its sub-pixel Gaussian PSF is splatted.
|
|
||||||
|
|
||||||
Build and render the default 1280 x 720 image:
|
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. Moving cameras are described by worldline and tetrad tracks.
|
||||||
|
|
||||||
|
## 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
|
```sh
|
||||||
make run
|
make -j
|
||||||
```
|
```
|
||||||
|
|
||||||
The program first creates `assets/sky_grid_5deg.csv` when it is missing. The
|
This builds both `build/Release/minkowski_sky` and
|
||||||
synthetic catalog places stars every 2 degrees on the union of longitude and
|
`build/Release/schwarzschild_sky`. For individual backends, Debug builds,
|
||||||
latitude lines spaced 10 degrees apart; the two poles are stored only once.
|
optional HDR/FITS output, HIP support, and regression checks, see
|
||||||
The eight octants (four 90-degree longitude sectors in each hemisphere)
|
[build.md](build.md).
|
||||||
alternate red `temperature_K = 3000` and blue `temperature_K = 12000`.
|
|
||||||
Red stars use `amplitude = 1`; blue stars use `amplitude = 0.00141095580387`,
|
|
||||||
which equalizes their CIE/linear-sRGB luminance under the renderer's blackbody
|
|
||||||
integration. Longitude boundaries belong to the sector to their east and the
|
|
||||||
equator to the northern hemisphere, so boundary stars have a deterministic
|
|
||||||
color.
|
|
||||||
The default output is PNG at `output/imgs/minkowski_sky.png`.
|
|
||||||
|
|
||||||
### Optional HIP PSF backend
|
## Prepare the stellar catalog
|
||||||
|
|
||||||
The default `PSF_BACKEND=cpu` uses the established OpenMP/private-HDR path.
|
The renderer accepts **any stellar catalog converted to the supported CSV
|
||||||
Build the direct-atomic HIP PSF backend explicitly with
|
format**: four columns containing ICRS right ascension and declination in
|
||||||
`PSF_BACKEND=hip`; it requires HIP/ROCm and a usable GPU agent, and writes a
|
degrees, temperature in kelvin, and amplitude, in that order. Use
|
||||||
separate `_hip` binary so it cannot overwrite the CPU renderer:
|
`--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
|
```sh
|
||||||
make PSF_BACKEND=hip SPACETIME=minkowski backend
|
|
||||||
./build/Release/minkowski_sky_hip --catalog assets/sky_grid_5deg.csv \
|
|
||||||
--output output/imgs/minkowski_sky_hip.png
|
|
||||||
```
|
|
||||||
|
|
||||||
The HIP backend accelerates only cache-eligible PSF events. Existing direct
|
|
||||||
fallbacks remain CPU reference evaluations, with an ordered HDR transfer before
|
|
||||||
and after each fallback. A HIP initialization, upload, kernel, or download
|
|
||||||
error terminates the render; it never switches to the CPU backend silently.
|
|
||||||
Use `make PSF_BACKEND=hip SPACETIME=minkowski hip-psf-test` for the small
|
|
||||||
GPU-vs-CPU cache-HDR regression. HIP renders also report event, batch, H2D,
|
|
||||||
kernel, and HDR-download timing after each frame. To bound diagnostic-event
|
|
||||||
storage, the report times at most the first 64 batches and labels the timed
|
|
||||||
batch count explicitly; the event and total-batch counts are not sampled.
|
|
||||||
|
|
||||||
## Movie PNG sequence (Phase A)
|
|
||||||
|
|
||||||
Movie mode consumes a canonical observer-track CSV rather than a fixed camera.
|
|
||||||
Each row stores coordinate time, proper time, Cartesian position, and the full
|
|
||||||
four-by-four tetrad (21 columns total). Generate the first reproducible
|
|
||||||
Minkowski benchmark—two coordinate seconds at 30 fps, accelerating from rest
|
|
||||||
to about `0.95c`—then render its numbered PNG frames:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
make clean && make
|
|
||||||
mkdir -p output/imgs
|
mkdir -p output/imgs
|
||||||
./build/minkowski_sky --write-minkowski-accel-track output/minkowski_accel_2s.csv \
|
./build/Release/minkowski_sky \
|
||||||
--duration 2 --fps 30 --proper-acceleration 1.52
|
--all-sky-catalog assets/2mass/processed/all_sky \
|
||||||
./build/minkowski_sky --observer-track output/minkowski_accel_2s.csv \
|
--look-ra-deg 296 --look-dec-deg 27 --fov-deg 72 \
|
||||||
--frames-dir output/imgs --frames-prefix minkowski_accel \
|
--width 3840 --height 2160 --exposure 1e12 \
|
||||||
--start-time 0 --duration 2 --fps 30 --exposure 1e-5
|
--output output/imgs/summer_triangle.png
|
||||||
```
|
```
|
||||||
|
|
||||||
This writes `minkowski_accel_000000.png` through
|
[](assets/images/summer_triangle.png)
|
||||||
`minkowski_accel_000060.png`. The renderer treats the CSV as its observer
|
|
||||||
input; the acceleration generator is only a reproducible flat-spacetime test
|
|
||||||
fixture. Movie mode collects all current frame-mesh vertices into a single
|
|
||||||
SoA ray pool, activates rays as a newest-to-oldest coordinate-time scan reaches
|
|
||||||
their observer event, and advances active rays to each slab boundary. The
|
|
||||||
analytic backends use logical slabs with no metric I/O; nmesh slab loading is
|
|
||||||
the next backend step. `--slab-duration` sets the coordinate-time width
|
|
||||||
(default `64`) for this current fixed-mesh pass. The current
|
|
||||||
synthetic test catalog uses global default exposure `1e-3`; the accelerated
|
|
||||||
benchmark explicitly uses `1e-5` because its physical Doppler blue shift
|
|
||||||
otherwise clips the later frames.
|
|
||||||
|
|
||||||
## Reuse a completed lens map
|
*4K reference image with exposure `1e12`. Click to view at full resolution.*
|
||||||
|
|
||||||
Ray tracing and adaptive mesh refinement are independent of catalog lookup,
|
Angles are in degrees; `--fov-deg` is the horizontal field of view. Exposure
|
||||||
PSF evaluation, exposure, and tone mapping. `--lens-map-output FILE` writes
|
is an adjustable display multiplier. Use `--verbose` for progress during long
|
||||||
the finalized local inverse-lens mesh to one versioned `.grlens` file after all
|
renders.
|
||||||
ray-trace/refinement generations finish; the same invocation still renders its
|
|
||||||
ordinary image. The file stores every final vertex's image position, camera
|
|
||||||
direction, infinity direction, frequency shift, terminal status, and the
|
|
||||||
triangle topology. It also stores the frame dimensions, horizontal FOV, and,
|
|
||||||
for a movie, all frame IDs and times.
|
|
||||||
|
|
||||||
For example, trace an analytic Schwarzschild frame once and retain the map:
|
### 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
|
```sh
|
||||||
make SPACETIME=schwarzschild backend
|
|
||||||
mkdir -p output/imgs output/maps
|
|
||||||
./build/Release/schwarzschild_sky --catalog assets/sky_grid_5deg.csv \
|
|
||||||
--width 640 --height 360 --coarse-cell-pixels 8 --fov-deg 60 \
|
|
||||||
--refine-max-level 2 --lens-map-output output/maps/schwarzschild.grlens \
|
|
||||||
--output output/imgs/schwarzschild_trace.png
|
|
||||||
```
|
|
||||||
|
|
||||||
Later, render that saved map with a different catalog, PSF, or exposure without
|
|
||||||
constructing an observer, spacetime source, or geodesic rays:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
./build/Release/schwarzschild_sky --lens-map-input output/maps/schwarzschild.grlens \
|
|
||||||
--catalog assets/sky_grid_5deg.csv --psf-fwhm-pixels 6 --psf-moffat-beta 3 \
|
|
||||||
--exposure 0.002 --output output/imgs/schwarzschild_restyled.png
|
|
||||||
```
|
|
||||||
|
|
||||||
`--lens-map-input` and `--lens-map-output` are mutually exclusive. An imported
|
|
||||||
map always retains its original pixel width, height, and horizontal FOV; an
|
|
||||||
explicit conflicting `--width`, `--height`, or `--fov-deg` is rejected. This is
|
|
||||||
intentional: the stored inverse map and PSF coordinates are in the original
|
|
||||||
pixel geometry. The reader validates the format version, finite values, unit
|
|
||||||
directions, triangle indices, and a per-frame CRC before rendering.
|
|
||||||
|
|
||||||
A movie export writes every final frame mesh into the same `.grlens` file.
|
|
||||||
Export it during the usual movie render, then import it with `--frames-dir` and
|
|
||||||
`--frames-prefix`; importing a multi-frame map does not require
|
|
||||||
`--observer-track`:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
./build/Release/minkowski_sky --lens-map-input output/maps/movie.grlens \
|
|
||||||
--catalog assets/sky_grid_5deg.csv --frames-dir output/imgs \
|
|
||||||
--frames-prefix restyled
|
|
||||||
```
|
|
||||||
|
|
||||||
PNG is the default output and the default build links `libpng`:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
make clean && make
|
|
||||||
mkdir -p output/imgs
|
mkdir -p output/imgs
|
||||||
./build/minkowski_sky --output output/imgs/minkowski_sky.png
|
./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
|
||||||
```
|
```
|
||||||
|
|
||||||
If `libpng` is unavailable, rebuild with `make clean && make ENABLE_PNG=0`.
|
This uses the reference image's rendering settings, including its
|
||||||
That intentionally selects the binary-PPM fallback, whose default path is
|
`--max-cache-psf-flux 1e8` preview approximation, which clips bright PSF wings
|
||||||
`output/imgs/minkowski_sky.ppm`; pass a `.ppm` path for explicit output.
|
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.
|
||||||
|
|
||||||
Run the flat-spacetime geodesic regression with:
|
The Schwarzschild camera points toward the hole. 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: 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
|
```sh
|
||||||
make test
|
|
||||||
```
|
|
||||||
|
|
||||||
This also checks that the Kerr--Schild metric remains finite at `r=2M` and
|
|
||||||
that the central ray from the default Schwarzschild camera is classified as
|
|
||||||
captured.
|
|
||||||
|
|
||||||
Build an independent analytic Schwarzschild executable in Cartesian ingoing
|
|
||||||
Kerr--Schild coordinates (regular at the horizon), then render the test catalog
|
|
||||||
to PNG:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
make clean && make SPACETIME=schwarzschild
|
|
||||||
mkdir -p output/imgs
|
mkdir -p output/imgs
|
||||||
./build/schwarzschild_sky --catalog assets/sky_grid_5deg.csv \
|
./build/Release/schwarzschild_sky \
|
||||||
--width 640 --height 360 --coarse-cell-pixels 8 --fov-deg 60 \
|
--max-cache-psf-flux 1e8 \
|
||||||
--output output/imgs/schwarzschild_test_catalog.png
|
--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
|
||||||
```
|
```
|
||||||
|
|
||||||
`SPACETIME=minkowski` (the default) and `SPACETIME=schwarzschild` select source
|
[](assets/images/schwarzschild_test_grid.png)
|
||||||
files at compile time, so each executable contains exactly one metric provider.
|
|
||||||
The Schwarzschild demonstration uses mass `M=1` and places a static camera at
|
|
||||||
coordinate radius `30` by default. `--look-ra-deg` and `--look-dec-deg`
|
|
||||||
define the direction from the camera to the hole; the camera is placed at the
|
|
||||||
opposite direction from the origin and its local forward axis points radially
|
|
||||||
inward. Use `--observer-radius R` to select any `R > 2`; it is a coordinate
|
|
||||||
radius in Cartesian Kerr--Schild coordinates. The backend escapes at `r=256`
|
|
||||||
and declares capture at `r=1.5`, safely inside the horizon at `r=2`. Those
|
|
||||||
rendering thresholds are Phase-1 demonstration values, not settled production
|
|
||||||
refinement or integration settings.
|
|
||||||
|
|
||||||
For a local radial boost relative to that static camera, pass
|
*4K test-grid reference image. Click to view at full resolution.*
|
||||||
`--observer-inward-speed V`, where `0 <= V < 1` is measured in the static
|
|
||||||
observer's orthonormal frame and positive values point toward the hole. The
|
|
||||||
default is `0`, preserving the static camera.
|
|
||||||
|
|
||||||
For rays that asymptote to the future horizon in coordinate-time backward
|
|
||||||
integration, the Schwarzschild demo also terminates at
|
|
||||||
`log(alpha p^0) = 8`. This is the normalized-momentum horizon diagnostic
|
|
||||||
already evolved by the integrator; it is disabled by default and does not
|
|
||||||
replace the AH-calibrated spatial capture criterion planned for nmesh data.
|
|
||||||
|
|
||||||
Useful options:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
./build/minkowski_sky --width 1920 --height 1080 --fov-deg 30 \
|
|
||||||
--catalog assets/sky_grid_5deg.csv --output output/imgs/frame.png
|
|
||||||
./build/minkowski_sky --catalog assets/2mass/processed/2mass_psc_m31_0p5deg_stars.csv \
|
|
||||||
--look-ra-deg 10.6847083 --look-dec-deg 41.26875 --fov-deg 1.8 \
|
|
||||||
--exposure 1e15 --output output/imgs/2mass_m31.png
|
|
||||||
./build/minkowski_sky --catalog assets/2mass/processed/2mass_psc_m44_1p0deg_stars.csv \
|
|
||||||
--look-ra-deg 129.99165 --look-dec-deg 19.54139 --fov-deg 2.0 \
|
|
||||||
--exposure 1e15 --width 1920 --height 1920 --output output/imgs/2mass_m44.png
|
|
||||||
./build/minkowski_sky --write-catalog assets/sky_grid_5deg.csv
|
|
||||||
```
|
|
||||||
|
|
||||||
The camera is a fixed inertial observer at coordinate position `(0,0,0)`,
|
|
||||||
with a tetrad whose forward direction is coordinate `-Z` and whose vertical
|
|
||||||
direction is `+Y`. The frame first triangulates the image plane, then traces
|
|
||||||
only its vertices backwards. Escaped endpoints form a triangulation on the
|
|
||||||
source sky. For every locally invertible triangle, catalog stars inside its
|
|
||||||
spherical source triangle are interpolated back to the image triangle and
|
|
||||||
splatted as PSFs. Consequently multiple image triangles naturally create
|
|
||||||
multiple images of the same star.
|
|
||||||
|
|
||||||
The ray state evolves `(x^i, Pi_i, log(alpha p^0))` in coordinate time with
|
|
||||||
RK4 using the 3+1 equations in Bohn et al. II.A, until the spacetime backend
|
|
||||||
classifies the ray. `spacetime.c` is the only module containing the Minkowski
|
|
||||||
metric or its infinity criterion; frame, observer, and integrator use only
|
|
||||||
`SpacetimeSource` and `MetricData`. The initial regular mesh size is exposed
|
|
||||||
as `--coarse-cell-pixels`; it is a Phase-0 sampling knob, not a settled
|
|
||||||
production refinement threshold.
|
|
||||||
|
|
||||||
### Adaptive image mesh refinement
|
|
||||||
|
|
||||||
Adaptive refinement is disabled by default (`--refine-max-level 0`), so the
|
|
||||||
existing coarse-mesh renders remain unchanged. When enabled, its defaults are
|
|
||||||
an absolute direction error of `1e-3` degrees, relative error `0.1`, minimum
|
|
||||||
long edge `0.5` pixels, minimum area `0.25` pixel-squared, and a provisional
|
|
||||||
minimum discrete-Jacobian magnitude of `1e-3`. Each value can be overridden
|
|
||||||
independently:
|
|
||||||
|
|
||||||
```text
|
|
||||||
--refine-max-level N
|
|
||||||
--refine-angle-abs-deg D
|
|
||||||
--refine-angle-rel R
|
|
||||||
--refine-jacobian-min J
|
|
||||||
--refine-min-edge-pixels P
|
|
||||||
--refine-min-area-pixels2 A
|
|
||||||
```
|
|
||||||
|
|
||||||
`N` caps the triangle refinement level. Let `e` be the angle between the
|
|
||||||
traced longest-edge midpoint direction and the normalized endpoint
|
|
||||||
interpolation, and let `s` be the angle between those two endpoint **camera
|
|
||||||
directions**. Both are evaluated internally in radians; the absolute CLI
|
|
||||||
threshold `D` is specified in degrees and converted before comparison. `s`
|
|
||||||
is the angular geometric size of the image triangle's test edge, not a
|
|
||||||
source-sky/lens-map length. A locally escaped triangle is split only when
|
|
||||||
**both** `e > D_rad` (the converted `--refine-angle-abs-deg D`) and
|
|
||||||
`e / max(s, 1e-15) > --refine-angle-rel`. `P` and `A`
|
|
||||||
prevent selecting a leaf already at or below the requested image-plane
|
|
||||||
long-edge and area scales.
|
|
||||||
Triangles whose three vertices disagree between capture and escape are split
|
|
||||||
independently of the direction-error thresholds, allowing the mesh to follow a
|
|
||||||
shadow boundary.
|
|
||||||
|
|
||||||
Independently of the midpoint geometry test, an all-escaped triangle also
|
|
||||||
computes the discrete lens Jacobian
|
|
||||||
`J = Omega_source / Omega_image`. Both signed solid angles use
|
|
||||||
`2 atan2(dot(a, cross(b,c)), 1 + dot(a,b) + dot(b,c) + dot(c,a))`, with the
|
|
||||||
ordered camera directions for `Omega_image` and their traced infinity
|
|
||||||
directions for `Omega_source`. A J-driven split requires **both** a shared
|
|
||||||
image edge whose incident triangles have opposite nonzero signs of `J` and
|
|
||||||
`min(abs(J_left), abs(J_right)) < --refine-jacobian-min`. It then requests
|
|
||||||
that shared edge on both leaves. Thus `|J|` bounds the fold selection instead
|
|
||||||
of widening it as a standalone critical-curve band. A negative sign is
|
|
||||||
physical parity and is retained. The `1e-3` default is deliberately
|
|
||||||
provisional and should be tuned with the small Schwarzschild refinement
|
|
||||||
diagnostic before being treated as a production threshold.
|
|
||||||
|
|
||||||
For a short Schwarzschild diagnostic that permits at most one actual split
|
|
||||||
generation, for example:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
./build/schwarzschild_sky --catalog assets/sky_grid_5deg.csv \
|
|
||||||
--width 48 --height 48 --coarse-cell-pixels 24 --fov-deg 40 \
|
|
||||||
--refine-max-level 1 --refine-angle-abs-deg 0.001 \
|
|
||||||
--refine-angle-rel 0.001 --refine-jacobian-min 0.001 \
|
|
||||||
--refine-min-edge-pixels 1 \
|
|
||||||
--refine-min-area-pixels2 1 --draw-mesh \
|
|
||||||
--output output/imgs/schwarzschild_refinement.png
|
|
||||||
```
|
|
||||||
|
|
||||||
For movies, each refinement generation completes the full newest-to-oldest
|
|
||||||
time-slab sweep before any probe becomes a mesh vertex. Newly added vertices
|
|
||||||
are therefore traced only by the next generation; the renderer never returns
|
|
||||||
to a slab that has already been released. At the start of every generation,
|
|
||||||
newly inserted vertices and geometry-only longest-edge probes for its new
|
|
||||||
leaves are collected together, so both ray sets use the same parallel
|
|
||||||
`RayPool` pass.
|
|
||||||
|
|
||||||
Catalog directions and `--look-ra-deg`/`--look-dec-deg` use standard
|
|
||||||
right-handed ICRS Cartesian axes: `+X` is RA 0 degrees/Dec 0 degrees, `+Y` is
|
|
||||||
RA 90 degrees/Dec 0 degrees, and `+Z` is the north celestial pole. The local
|
|
||||||
camera axes are forward, celestial north, and celestial west, so an image with
|
|
||||||
north up has decreasing RA to the right. The defaults preserve the original
|
|
||||||
`-Z` view. `--exposure` converts a catalog's physical flux
|
|
||||||
normalization to the prototype HDR scale. The current synthetic catalog is
|
|
||||||
calibrated for default exposure `1e-3`; a 2MASS blackbody normalization in
|
|
||||||
steradians requires a much larger display exposure such as the example above.
|
|
||||||
The optics path
|
|
||||||
integrates each fitted Planck spectrum through CIE 1931 color-matching functions
|
|
||||||
and converts the resulting radiance to linear sRGB; it does not use an empirical
|
|
||||||
color-temperature RGB approximation.
|
|
||||||
|
|
||||||
Point sources use a flux-normalized circular Moffat PSF by default
|
|
||||||
(`--psf-fwhm-pixels 2.7 --psf-moffat-beta 4.5`). The FWHM matches the former
|
|
||||||
1.15-pixel Gaussian core while the Moffat wings remain continuous; both values
|
|
||||||
are display/optics calibration parameters.
|
|
||||||
|
|
||||||
The default renderer builds one immutable, process-wide 64-by-64 sub-pixel
|
|
||||||
Moffat lookup kernel. Its weights are pixel-area integrals and are bilinearly
|
|
||||||
interpolated between phase tables. The renderer reports its build time and
|
|
||||||
cached/direct-fallback image counts. Pass `--psf-direct` to use the slower
|
|
||||||
8-point quadrature reference evaluator for regression comparisons; an image
|
|
||||||
whose required HDR-tail support exceeds the cache radius selects that reference
|
|
||||||
path automatically.
|
|
||||||
|
|
||||||
`--psf-relative-tail R` controls the maximum omitted PSF tail fraction per
|
|
||||||
image; it defaults to `1e-8`. Larger values intentionally shorten the Moffat
|
|
||||||
support and rebuild the immutable cache at the corresponding radius, which is
|
|
||||||
useful when a faster, lower-fidelity render is acceptable.
|
|
||||||
|
|
||||||
`--psf-min-y Y` defaults to `0` (disabled). A positive value is a linear-HDR
|
|
||||||
luminance cutoff: a PSF stops where its continuous Moffat Y profile falls below
|
|
||||||
`Y`, and an image whose central value is already below `Y` is omitted. The
|
|
||||||
final PSF report counts such omitted events and emits a warning when any occur.
|
|
||||||
|
|
||||||
For bounded preview renders, `--max-cache-psf-flux F` (default `1`) allows
|
|
||||||
images with `1 < flux <= F` to use the existing cache instead of the direct
|
|
||||||
evaluator. This does not rebuild or enlarge the cache: the image retains its
|
|
||||||
true core flux, color, and sub-pixel position, while its Moffat wing is clipped
|
|
||||||
at the existing cache radius. Images above `F` retain the direct fallback.
|
|
||||||
`--max-magnification M` (default unlimited) caps the per-triangle rendering
|
|
||||||
magnification before flux is formed; it is an explicit preview approximation.
|
|
||||||
|
|
||||||
The PSF-cache completion line is printed before tracing and catalog splatting
|
|
||||||
begin. For long renders, pass `--verbose` to print catalog-prefetch state,
|
|
||||||
splat-worker local heartbeats (8, 16, 32, ... completed triangles per worker),
|
|
||||||
and image-write boundaries. The worker heartbeats use neither global progress
|
|
||||||
accounting nor cross-worker synchronization.
|
|
||||||
Verbose ray-trace output reports the initial mesh trace and refinement stages
|
|
||||||
for single frames; movie mode additionally reports each generation's sample
|
|
||||||
count and each time slab's activation and terminal-ray summary.
|
|
||||||
Movie renders always print one summary per time slab; `--verbose` also prints
|
|
||||||
the ray counts before each slab is loaded.
|
|
||||||
|
|
||||||
To preserve a render for later exposure and tone-mapping work, build the desired
|
|
||||||
backend with `ENABLE_HDR=1`, for example `make SPACETIME=schwarzschild
|
|
||||||
ENABLE_HDR=1`. This produces `build/Release/schwarzschild_sky`,
|
|
||||||
which accepts `--hdr-output`. This switch writes the HDR file next to the
|
|
||||||
ordinary output, replacing its extension with `_HDR.fits`; for example,
|
|
||||||
`--output output/imgs/ring.png --hdr-output` writes
|
|
||||||
`output/imgs/ring_HDR.fits`. It writes the pre-tone-mapping RGB
|
|
||||||
framebuffer as a three-plane, 32-bit float FITS image. Values remain linear HDR
|
|
||||||
at the renderer's arbitrary scale; no tone mapping or per-frame normalization
|
|
||||||
is applied. The ordinary
|
|
||||||
binaries do not contain this option or writer.
|
|
||||||
|
|
||||||
The FITS header describes a synthetic 8640-by-5760, 36-by-24 mm full-frame
|
|
||||||
sensor with 4.1667 um pixels. Each render records its active centered crop and
|
|
||||||
derives `FOCALLEN` from that render's width and horizontal `--fov-deg`; these
|
|
||||||
camera fields support plate-solving workflows but do not calibrate flux.
|
|
||||||
|
|
||||||
Pass `--draw-mesh` to alpha-composite image-plane triangle edges as
|
|
||||||
one-pixel-wide 0.5 linear-gray diagnostic lines at 0.5 opacity. The line
|
|
||||||
rasterizer uses coverage-based antialiasing.
|
|
||||||
+102
@@ -0,0 +1,102 @@
|
|||||||
|
# GR 4D ray tracing
|
||||||
|
|
||||||
|
[English](README.md) | **简体中文**
|
||||||
|
|
||||||
|
一个以物理正确性为优先的离线时空渲染器。项目旨在通过沿四维时空向过去追踪光线,将双黑洞并合等随时间演化的数值相对论模拟渲染为 4K 视频。
|
||||||
|
|
||||||
|
[](assets/images/schwarzschild_galactic_center.png)
|
||||||
|
|
||||||
|
*从半径 100 M 处的相机观察 Schwarzschild 时空中的 2MASS 银心方向星场。点击图片查看完整 4K 图像;[渲染命令见下文](#示例schwarzschild-时空中的银心方向星场)。*
|
||||||
|
|
||||||
|
恒星以独立的星表点源表示,保留方向、温度和振幅。渲染器将它们映射到相机图像中,处理多像、引力透镜放大和频移,再将保留亚像素位置的点扩散函数(PSF)累积到 HDR 图像。运动相机由世界线与四标架(tetrad)轨迹描述。
|
||||||
|
|
||||||
|
## 当前进展
|
||||||
|
|
||||||
|
当前实现支持解析 **Minkowski** 与 **Schwarzschild** 时空、单张图像、基于观测者轨迹的图像序列、自适应透镜网格,以及可复用的透镜映射文件。程序主要使用 C 编写,通过 OpenMP 实现 CPU 并行;可选的 HIP 后端用于加速 PSF 累积。
|
||||||
|
|
||||||
|
[Nmesh](https://github.com/nmeshsource/nmesh) 数值时空后端和双黑洞(BBH)渲染仍在规划中。当前范围为黑洞捕获与远处恒星背景,暂不包含局域物质辐射、吸积盘或等离子体。架构与开发路线参见[设计文档](nr_spacetime_movie_renderer_design.md)。
|
||||||
|
|
||||||
|
## 编译
|
||||||
|
|
||||||
|
默认构建需要支持 OpenMP 的 C11 编译器、GNU Make,以及 libpng 开发文件。在仓库根目录运行:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make -j
|
||||||
|
```
|
||||||
|
|
||||||
|
这会同时生成 `build/Release/minkowski_sky` 和 `build/Release/schwarzschild_sky`。单独编译某个后端、Debug 构建、可选 HDR/FITS 输出、HIP 支持及回归检查,参见 [build.md](build.md)(英文)。
|
||||||
|
|
||||||
|
## 准备星表
|
||||||
|
|
||||||
|
渲染器支持**转换为规定 CSV 格式的任意星表**:四列依次为 ICRS 赤经、赤纬(单位均为度)、温度(单位为开尔文)和振幅。使用 `--catalog PATH` 加载单个 CSV 文件。
|
||||||
|
|
||||||
|
**2MASS 是本项目推荐的巡天星表**,项目提供配套的下载与处理脚本。具体操作参见 [assets/2mass/README.md](assets/2mass/README.md)(英文)。完整下载大约需要**三到四天**,因此建议**优先联系我获取压缩包**。下方示例使用的已处理星表分块应放在 `assets/2mass/processed/all_sky/`。
|
||||||
|
|
||||||
|
仓库提供的 [assets/sky_grid_5deg.csv](assets/sky_grid_5deg.csv) 是用于几何验证与回归测试的合成恒星网格。无需下载巡天数据,即可通过 `--catalog assets/sky_grid_5deg.csv` 使用,参见下方[测试网格示例](#示例叠加网格的合成测试星表)。
|
||||||
|
|
||||||
|
## 渲染示例
|
||||||
|
|
||||||
|
以下示例展示星区、时空和相机设置的几种组合。完成编译并准备好星表后,可以按需调整命令中的视场、观测者位置和渲染参数。可用的控制选项与工作流程参见 [usage.md](usage.md)(英文)。
|
||||||
|
|
||||||
|
### 示例:平直时空中的夏季大三角
|
||||||
|
|
||||||
|
这个示例渲染夏季大三角附近的星场:
|
||||||
|
|
||||||
|
```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)
|
||||||
|
|
||||||
|
*曝光为 `1e12` 的 4K 参考图像。点击查看完整分辨率。*
|
||||||
|
|
||||||
|
角度单位为度,`--fov-deg` 表示水平视场角。曝光是可调节的显示倍率。长时间渲染时可使用 `--verbose` 查看进度。
|
||||||
|
|
||||||
|
### 示例:Schwarzschild 时空中的银心方向星场
|
||||||
|
|
||||||
|
这个示例将相机放在半径 100 M 处,渲染本页顶部展示的、受到引力透镜作用的银心方向星场:
|
||||||
|
|
||||||
|
```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
|
||||||
|
```
|
||||||
|
|
||||||
|
这里使用参考图像的渲染设置,包括 `--max-cache-psf-flux 1e8` 这一预览近似:它将明亮 PSF 的翼部截断在缓存半径内。[原始 benchmark 记录](benchmarks/2mass_galactic_center_blackhole.md)保留了命令与终端输出;上述命令省略了可选的 HDR 导出。
|
||||||
|
|
||||||
|
Schwarzschild 相机朝向黑洞。自适应细分默认关闭,应根据所需图像精度配置。相机控制、图像序列、透镜映射复用、PSF 设置及 HDR 输出参见 [usage.md](usage.md)(英文)。两个可执行文件都可通过 `--help` 查看完整选项。
|
||||||
|
|
||||||
|
### 示例:叠加网格的合成测试星表
|
||||||
|
|
||||||
|
这个示例使用 `assets/sky_grid_5deg.csv` 检查 Schwarzschild 时空中的引力透镜效果与自适应网格细分。`--draw-mesh` 会叠加显示最终的像平面三角网格。
|
||||||
|
|
||||||
|
```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 测试网格参考图像。点击查看完整分辨率。*
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 12 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 11 MiB |
@@ -0,0 +1,27 @@
|
|||||||
|
Git hash: dd8cf29dac557c881e5df1db15a58fae15294967
|
||||||
|
|
||||||
|
```
|
||||||
|
❯ time ./build/Release/schwarzschild_sky \
|
||||||
|
--psf-relative-tail 1e-8 \
|
||||||
|
--psf-min-y 0 \
|
||||||
|
--max-cache-psf-flux 1e8 \
|
||||||
|
--all-sky-catalog assets/2mass/processed/all_sky \
|
||||||
|
--refine-max-level 4 \
|
||||||
|
--refine-jacobian-min 0.2 \
|
||||||
|
--width 3840 --height 2160 \
|
||||||
|
--look-ra-deg 262.5 --look-dec-deg -30 \
|
||||||
|
--fov-deg 45 \
|
||||||
|
--coarse-cell-pixels 16 \
|
||||||
|
--exposure 1e13 \
|
||||||
|
--psf-fwhm-pixels 2.7 --psf-moffat-beta 4.5 \
|
||||||
|
--catalog-load-workers 4 \
|
||||||
|
--observer-radius 100 \
|
||||||
|
--hdr-output \
|
||||||
|
--output output/imgs/2mass_galactic_center_schwarzschild_R100_4k_1e13_beta4.5_16_4-full.png
|
||||||
|
PSF cache ready: 64x64 phases, radius 47 px, relative tail 1e-08, tail abs 1e-06, boundary 1e-07, build 0.693 s
|
||||||
|
|
||||||
|
Catalog prefetch: 64440 requested, 64440 newly loaded (343363141 stars), 0 unavailable in 48.016 s; 4 loader workers
|
||||||
|
Rendered 598308919 images from 343363141 catalog stars to output/imgs/2mass_galactic_center_schwarzschild_R100_4k_1e13_beta4.5_16_4-full.png (ok)
|
||||||
|
PSF splats: cached 598308919, cached wing-clipped 1365, direct fallbacks 0, discarded below min-Y 0
|
||||||
|
./build/Release/schwarzschild_sky --psf-relative-tail 1e-8 --psf-min-y 0 1e8 21346.08s user 132.97s system 1520% cpu 23:32.47 total
|
||||||
|
```
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
# Build guide
|
||||||
|
|
||||||
|
Run these commands from the repository root. The build uses GNU Make and
|
||||||
|
produces standalone executables under `build/Release/` or `build/Debug/`.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
The default CPU build needs:
|
||||||
|
|
||||||
|
- A C11 compiler and OpenMP runtime (for example, GCC with libgomp).
|
||||||
|
- GNU Make.
|
||||||
|
- libpng headers and library for PNG output.
|
||||||
|
|
||||||
|
Optional dependencies are CFITSIO and `pkg-config` for HDR/FITS output, and
|
||||||
|
HIP/ROCm with `hipcc` and a compatible GPU for HIP PSF accumulation.
|
||||||
|
|
||||||
|
## CPU build
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make -j
|
||||||
|
```
|
||||||
|
|
||||||
|
With no explicit `SPACETIME` setting, this builds both supported spacetimes:
|
||||||
|
|
||||||
|
| Executable | Spacetime |
|
||||||
|
| --- | --- |
|
||||||
|
| `build/Release/minkowski_sky` | Flat Minkowski spacetime |
|
||||||
|
| `build/Release/schwarzschild_sky` | Analytic Schwarzschild in ingoing Kerr–Schild coordinates |
|
||||||
|
|
||||||
|
To build only one:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make -j SPACETIME=minkowski backend
|
||||||
|
make -j SPACETIME=schwarzschild backend
|
||||||
|
```
|
||||||
|
|
||||||
|
Each executable contains one metric provider, selected at compile time.
|
||||||
|
`PSF_BACKEND=cpu` is the default. Release builds use `-O2 -DNDEBUG`; the
|
||||||
|
default compiler flags also include `-march=native`, targeting the build
|
||||||
|
machine's CPU. For a binary intended for other CPUs, override `CFLAGS`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make -B -j CFLAGS='-std=c11 -pipe -Wall -Wextra -Wpedantic'
|
||||||
|
```
|
||||||
|
|
||||||
|
For a Debug build (`-O0 -g3`):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make -j BUILD_TYPE=Debug
|
||||||
|
```
|
||||||
|
|
||||||
|
Debug executables are placed in `build/Debug/`.
|
||||||
|
|
||||||
|
## Output formats
|
||||||
|
|
||||||
|
PNG is enabled by default. If libpng is unavailable, build with binary PPM
|
||||||
|
output instead and use a `.ppm` output filename:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make -B -j ENABLE_PNG=0
|
||||||
|
```
|
||||||
|
|
||||||
|
To enable the optional `--hdr-output` switch, install CFITSIO and `pkg-config`,
|
||||||
|
then build the desired spacetime with `ENABLE_HDR=1`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make -j SPACETIME=schwarzschild ENABLE_HDR=1 backend
|
||||||
|
```
|
||||||
|
|
||||||
|
The executable keeps its usual name, `build/Release/schwarzschild_sky`.
|
||||||
|
`--hdr-output` writes a linear RGB FITS file alongside the ordinary
|
||||||
|
single-frame image; see [usage.md](usage.md#hdr-output). Use `ENABLE_HDR=0`
|
||||||
|
to rebuild without this feature.
|
||||||
|
|
||||||
|
## Optional HIP PSF acceleration
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make -j PSF_BACKEND=hip SPACETIME=minkowski backend
|
||||||
|
make -j PSF_BACKEND=hip SPACETIME=schwarzschild backend
|
||||||
|
```
|
||||||
|
|
||||||
|
These produce `build/Release/minkowski_sky_hip` and
|
||||||
|
`build/Release/schwarzschild_sky_hip`, separately from the CPU executables.
|
||||||
|
`HIPCC` can override the default `hipcc` command. `ENABLE_HDR=1` can be combined
|
||||||
|
with either HIP build.
|
||||||
|
|
||||||
|
HIP accelerates cache-eligible PSF accumulation; ray tracing and catalog
|
||||||
|
mapping remain on the CPU. PSFs requiring direct evaluation retain the CPU
|
||||||
|
reference path with ordered HDR transfers. HIP initialization or execution
|
||||||
|
errors terminate the render instead of silently selecting the CPU backend.
|
||||||
|
|
||||||
|
## Rebuilding and checks
|
||||||
|
|
||||||
|
Build type, spacetime, HDR, and PSF backend configurations have separate object
|
||||||
|
paths. Changes to flags such as `ENABLE_PNG`, `CC`, or `CFLAGS` require a forced
|
||||||
|
rebuild with `make -B` and the intended settings. `make clean` removes the
|
||||||
|
entire `build/` directory; keep rendered images and other retained output
|
||||||
|
under `output/`.
|
||||||
|
|
||||||
|
Inspect the available runtime options:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./build/Release/minkowski_sky --help
|
||||||
|
./build/Release/schwarzschild_sky --help
|
||||||
|
```
|
||||||
|
|
||||||
|
Run CPU regression checks:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make test
|
||||||
|
```
|
||||||
|
|
||||||
|
The HIP regression requires an actual compatible GPU. The Make target builds
|
||||||
|
the test executable; run it separately:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make PSF_BACKEND=hip SPACETIME=minkowski hip-psf-test
|
||||||
|
./build/Release/test_hip_psf
|
||||||
|
```
|
||||||
|
|
||||||
|
For rendering with real stellar data, continue with [README.md](README.md#prepare-the-stellar-catalog)
|
||||||
|
and the [rendering guide](usage.md).
|
||||||
@@ -0,0 +1,239 @@
|
|||||||
|
# Rendering guide
|
||||||
|
|
||||||
|
See [README.md](README.md) for the project overview and a first 2MASS render,
|
||||||
|
and [build.md](build.md) for compilation. Commands below run from the repository
|
||||||
|
root and use the default Release binaries. Run a binary with `--help` for its
|
||||||
|
complete option list and defaults.
|
||||||
|
|
||||||
|
## Catalog input
|
||||||
|
|
||||||
|
Use `--all-sky-catalog assets/2mass/processed/all_sky` for the tiled 2MASS
|
||||||
|
catalog, or `--catalog PATH` for a single processed CSV. Acquisition and
|
||||||
|
processing are documented in [assets/2mass/README.md](assets/2mass/README.md).
|
||||||
|
2MASS blackbody amplitudes need a much larger display exposure than the
|
||||||
|
synthetic test catalog; `--exposure 1e15` is a starting point, to be adjusted
|
||||||
|
for the field and camera.
|
||||||
|
|
||||||
|
## Schwarzschild camera
|
||||||
|
|
||||||
|
`schwarzschild_sky` uses an analytic Schwarzschild metric in Cartesian ingoing
|
||||||
|
Kerr–Schild coordinates, with mass `M=1`. The default camera is static at
|
||||||
|
coordinate radius `30`. `--look-ra-deg` and `--look-dec-deg` set the direction
|
||||||
|
from the camera to the hole; the camera is placed on the opposite side of the
|
||||||
|
origin and points radially inward. `--observer-radius R` requires `R > 2`.
|
||||||
|
`--observer-inward-speed V` applies a local inward boost relative to the static
|
||||||
|
observer, with `0 <= V < 1` and default `0`.
|
||||||
|
|
||||||
|
The analytic setup uses escape radius `256` and capture radius `1.5`, inside
|
||||||
|
the horizon at `r=2`. These are current demonstration settings; they do not
|
||||||
|
establish termination criteria for future numerical-relativity data.
|
||||||
|
|
||||||
|
## Movie image sequences
|
||||||
|
|
||||||
|
Movie mode reads an observer-track CSV containing coordinate time, proper
|
||||||
|
time, Cartesian position, and a full four-by-four tetrad (21 columns). The
|
||||||
|
track must cover the requested frame times. The following generates a sample
|
||||||
|
accelerating Minkowski trajectory and renders it against the 2MASS sky:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir -p output/imgs
|
||||||
|
./build/Release/minkowski_sky --write-minkowski-accel-track output/minkowski_accel_2s.csv \
|
||||||
|
--duration 2 --fps 30 --proper-acceleration 1.52
|
||||||
|
./build/Release/minkowski_sky --observer-track output/minkowski_accel_2s.csv \
|
||||||
|
--all-sky-catalog assets/2mass/processed/all_sky \
|
||||||
|
--frames-dir output/imgs --frames-prefix minkowski_accel \
|
||||||
|
--start-time 0 --duration 2 --fps 30 --exposure 1e15
|
||||||
|
```
|
||||||
|
|
||||||
|
The inclusive time interval produces frames `minkowski_accel_000000.png`
|
||||||
|
through `minkowski_accel_000060.png`. Exposure may need adjustment as Doppler
|
||||||
|
shifts change the brightness. The trajectory generator is a flat-spacetime
|
||||||
|
example; other camera motions are supplied through observer-track CSVs.
|
||||||
|
Output is an image sequence; video encoding is a separate step.
|
||||||
|
|
||||||
|
Movie rays from all frames share a newest-to-oldest coordinate-time sweep.
|
||||||
|
`--slab-duration` sets its time-slab width (default `64`). The current analytic
|
||||||
|
backends use logical slabs without metric I/O; [Nmesh](https://github.com/nmeshsource/nmesh) metric loading remains
|
||||||
|
future work.
|
||||||
|
|
||||||
|
## Reuse a completed lens map
|
||||||
|
|
||||||
|
`--lens-map-output FILE` saves the finalized inverse-lens mesh after tracing
|
||||||
|
and refinement, while also rendering the image normally. It stores the
|
||||||
|
geometry, frequency shifts, terminal statuses, triangle topology, and frame
|
||||||
|
metadata in a versioned `.grlens` file. This allows later catalog, PSF, and
|
||||||
|
exposure changes without repeating ray tracing.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir -p output/imgs output/maps
|
||||||
|
./build/Release/schwarzschild_sky \
|
||||||
|
--all-sky-catalog assets/2mass/processed/all_sky \
|
||||||
|
--width 640 --height 360 --coarse-cell-pixels 8 --fov-deg 60 \
|
||||||
|
--refine-max-level 2 --exposure 1e15 \
|
||||||
|
--lens-map-output output/maps/schwarzschild.grlens \
|
||||||
|
--output output/imgs/schwarzschild_trace.png
|
||||||
|
./build/Release/schwarzschild_sky \
|
||||||
|
--lens-map-input output/maps/schwarzschild.grlens \
|
||||||
|
--all-sky-catalog assets/2mass/processed/all_sky \
|
||||||
|
--psf-fwhm-pixels 6 --psf-moffat-beta 3 --exposure 1e15 \
|
||||||
|
--output output/imgs/schwarzschild_restyled.png
|
||||||
|
```
|
||||||
|
|
||||||
|
Import and export are mutually exclusive. Imported maps retain their original
|
||||||
|
pixel dimensions, horizontal FOV, and mesh resolution; they cannot be refined
|
||||||
|
on import. Explicit conflicting dimensions or FOV are rejected. The reader
|
||||||
|
checks the format version, finite values, unit directions, triangle indices,
|
||||||
|
and per-frame CRCs.
|
||||||
|
|
||||||
|
A movie export stores all final frame meshes in one file. To render it again,
|
||||||
|
pass `--lens-map-input FILE`, the catalog, `--frames-dir DIR`, and
|
||||||
|
`--frames-prefix NAME`; no observer track is needed on import.
|
||||||
|
|
||||||
|
## Adaptive image mesh refinement
|
||||||
|
|
||||||
|
Adaptive refinement is disabled by default (`--refine-max-level 0`), so the
|
||||||
|
existing coarse-mesh renders remain unchanged. When enabled, its defaults are
|
||||||
|
an absolute direction error of `1e-3` degrees, relative error `0.1`, minimum
|
||||||
|
long edge `0.5` pixels, minimum area `0.25` pixel-squared, and a provisional
|
||||||
|
minimum discrete-Jacobian magnitude of `1e-3`. Each value can be overridden
|
||||||
|
independently:
|
||||||
|
|
||||||
|
```text
|
||||||
|
--refine-max-level N
|
||||||
|
--refine-angle-abs-deg D
|
||||||
|
--refine-angle-rel R
|
||||||
|
--refine-jacobian-min J
|
||||||
|
--refine-min-edge-pixels P
|
||||||
|
--refine-min-area-pixels2 A
|
||||||
|
```
|
||||||
|
|
||||||
|
`N` caps the triangle refinement level. Let `e` be the angle between the
|
||||||
|
traced longest-edge midpoint direction and the normalized endpoint
|
||||||
|
interpolation, and let `s` be the angle between those two endpoint **camera
|
||||||
|
directions**. Both are evaluated internally in radians; the absolute CLI
|
||||||
|
threshold `D` is specified in degrees and converted before comparison. `s`
|
||||||
|
is the angular geometric size of the image triangle's test edge, not a
|
||||||
|
source-sky/lens-map length. A locally escaped triangle is split only when
|
||||||
|
**both** `e > D_rad` (the converted `--refine-angle-abs-deg D`) and
|
||||||
|
`e / max(s, 1e-15) > --refine-angle-rel`. `P` and `A`
|
||||||
|
prevent selecting a leaf already at or below the requested image-plane
|
||||||
|
long-edge and area scales.
|
||||||
|
Triangles whose three vertices disagree between capture and escape are split
|
||||||
|
independently of the direction-error thresholds, allowing the mesh to follow a
|
||||||
|
shadow boundary.
|
||||||
|
|
||||||
|
Independently of the midpoint geometry test, an all-escaped triangle also
|
||||||
|
computes the discrete lens Jacobian
|
||||||
|
`J = Omega_source / Omega_image`. Both signed solid angles use
|
||||||
|
`2 atan2(dot(a, cross(b,c)), 1 + dot(a,b) + dot(b,c) + dot(c,a))`, with the
|
||||||
|
ordered camera directions for `Omega_image` and their traced infinity
|
||||||
|
directions for `Omega_source`. A J-driven split requires **both** a shared
|
||||||
|
image edge whose incident triangles have opposite nonzero signs of `J` and
|
||||||
|
`min(abs(J_left), abs(J_right)) < --refine-jacobian-min`. It then requests
|
||||||
|
that shared edge on both leaves. Thus `|J|` bounds the fold selection instead
|
||||||
|
of widening it as a standalone critical-curve band. A negative sign is
|
||||||
|
physical parity and is retained. The `1e-3` default is deliberately
|
||||||
|
provisional and should be tuned with the small Schwarzschild refinement
|
||||||
|
diagnostic before being treated as a production threshold.
|
||||||
|
|
||||||
|
For a small mesh diagnostic using the synthetic catalog:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./build/Release/schwarzschild_sky --catalog assets/sky_grid_5deg.csv \
|
||||||
|
--width 48 --height 48 --coarse-cell-pixels 24 --fov-deg 40 \
|
||||||
|
--refine-max-level 1 --refine-angle-abs-deg 0.001 \
|
||||||
|
--refine-angle-rel 0.001 --refine-jacobian-min 0.001 \
|
||||||
|
--refine-min-edge-pixels 1 \
|
||||||
|
--refine-min-area-pixels2 1 --draw-mesh \
|
||||||
|
--output output/imgs/schwarzschild_refinement.png
|
||||||
|
```
|
||||||
|
|
||||||
|
For movies, each refinement generation completes the full newest-to-oldest
|
||||||
|
time-slab sweep before any probe becomes a mesh vertex. Newly added vertices
|
||||||
|
are therefore traced only by the next generation; the renderer never returns
|
||||||
|
to a slab that has already been released. At the start of every generation,
|
||||||
|
newly inserted vertices and geometry-only longest-edge probes for its new
|
||||||
|
leaves are collected together, so both ray sets use the same parallel
|
||||||
|
`RayPool` pass.
|
||||||
|
|
||||||
|
## Camera directions and optics
|
||||||
|
|
||||||
|
Catalog directions and `--look-ra-deg`/`--look-dec-deg` use standard
|
||||||
|
right-handed ICRS Cartesian axes: `+X` is RA 0 degrees/Dec 0 degrees, `+Y` is
|
||||||
|
RA 90 degrees/Dec 0 degrees, and `+Z` is the north celestial pole. The local
|
||||||
|
camera axes are forward, celestial north, and celestial west, so an image with
|
||||||
|
north up has decreasing RA to the right. The defaults preserve the original
|
||||||
|
`-Z` view. `--exposure` converts a catalog's physical flux
|
||||||
|
normalization to the prototype HDR scale. The current synthetic catalog is
|
||||||
|
calibrated for default exposure `1e-3`; a 2MASS blackbody normalization in
|
||||||
|
steradians requires a much larger display exposure such as the example above.
|
||||||
|
The optics path
|
||||||
|
integrates each fitted Planck spectrum through CIE 1931 color-matching functions
|
||||||
|
and converts the resulting radiance to linear sRGB; it does not use an empirical
|
||||||
|
color-temperature RGB approximation.
|
||||||
|
|
||||||
|
Point sources use a flux-normalized circular Moffat PSF by default
|
||||||
|
(`--psf-fwhm-pixels 2.7 --psf-moffat-beta 4.5`). The FWHM matches the former
|
||||||
|
1.15-pixel Gaussian core while the Moffat wings remain continuous; both values
|
||||||
|
are display/optics calibration parameters.
|
||||||
|
|
||||||
|
The default renderer builds one immutable, process-wide 64-by-64 sub-pixel
|
||||||
|
Moffat lookup kernel. Its weights are pixel-area integrals and are bilinearly
|
||||||
|
interpolated between phase tables. The renderer reports its build time and
|
||||||
|
cached/direct-fallback image counts. Pass `--psf-direct` to use the slower
|
||||||
|
8-point quadrature reference evaluator for regression comparisons; an image
|
||||||
|
whose required HDR-tail support exceeds the cache radius selects that reference
|
||||||
|
path automatically.
|
||||||
|
|
||||||
|
`--psf-relative-tail R` controls the maximum omitted PSF tail fraction per
|
||||||
|
image; it defaults to `1e-8`. Larger values intentionally shorten the Moffat
|
||||||
|
support and rebuild the immutable cache at the corresponding radius, which is
|
||||||
|
useful when a faster, lower-fidelity render is acceptable.
|
||||||
|
|
||||||
|
`--psf-min-y Y` defaults to `0` (disabled). A positive value is a linear-HDR
|
||||||
|
luminance cutoff: a PSF stops where its continuous Moffat Y profile falls below
|
||||||
|
`Y`, and an image whose central value is already below `Y` is omitted. The
|
||||||
|
final PSF report counts such omitted events and emits a warning when any occur.
|
||||||
|
|
||||||
|
For bounded preview renders, `--max-cache-psf-flux F` (default `1`) allows
|
||||||
|
images with `1 < flux <= F` to use the existing cache instead of the direct
|
||||||
|
evaluator. This does not rebuild or enlarge the cache: the image retains its
|
||||||
|
true core flux, color, and sub-pixel position, while its Moffat wing is clipped
|
||||||
|
at the existing cache radius. Images above `F` retain the direct fallback.
|
||||||
|
`--max-magnification M` (default unlimited) caps the per-triangle rendering
|
||||||
|
magnification before flux is formed; it is an explicit preview approximation.
|
||||||
|
|
||||||
|
## Progress and diagnostics
|
||||||
|
|
||||||
|
The PSF-cache completion line is printed before tracing and catalog splatting
|
||||||
|
begin. For long renders, pass `--verbose` to print catalog-prefetch state,
|
||||||
|
splat-worker local heartbeats (8, 16, 32, ... completed triangles per worker),
|
||||||
|
and image-write boundaries. The worker heartbeats use neither global progress
|
||||||
|
accounting nor cross-worker synchronization.
|
||||||
|
Verbose ray-trace output reports the initial mesh trace and refinement stages
|
||||||
|
for single frames; movie mode additionally reports each generation's sample
|
||||||
|
count and each time slab's activation and terminal-ray summary.
|
||||||
|
Movie renders always print one summary per time slab; `--verbose` also prints
|
||||||
|
the ray counts before each slab is loaded.
|
||||||
|
|
||||||
|
Pass `--draw-mesh` to alpha-composite image-plane triangle edges as
|
||||||
|
one-pixel-wide 0.5 linear-gray diagnostic lines at 0.5 opacity. The line
|
||||||
|
rasterizer uses coverage-based antialiasing.
|
||||||
|
|
||||||
|
## HDR output
|
||||||
|
|
||||||
|
To preserve a single-frame render for later exposure and tone-mapping work,
|
||||||
|
build with `ENABLE_HDR=1` as described in [build.md](build.md). This produces `build/Release/schwarzschild_sky`,
|
||||||
|
which accepts `--hdr-output`. This switch writes the HDR file next to the
|
||||||
|
ordinary output, replacing its extension with `_HDR.fits`; for example,
|
||||||
|
`--output output/imgs/ring.png --hdr-output` writes
|
||||||
|
`output/imgs/ring_HDR.fits`. It writes the pre-tone-mapping RGB
|
||||||
|
framebuffer as a three-plane, 32-bit float FITS image. Values remain linear HDR
|
||||||
|
at the renderer's arbitrary scale; no tone mapping or per-frame normalization
|
||||||
|
is applied. The ordinary
|
||||||
|
binaries do not contain this option or writer.
|
||||||
|
|
||||||
|
The FITS header describes a synthetic 8640-by-5760, 36-by-24 mm full-frame
|
||||||
|
sensor with 4.1667 um pixels. Each render records its active centered crop and
|
||||||
|
derives `FOCALLEN` from that render's width and horizontal `--fov-deg`; these
|
||||||
|
camera fields support plate-solving workflows but do not calibrate flux.
|
||||||
Reference in new issue
Block a user