Color antialiased half-edges by ray outcome with configurable Catppuccin colors and default opacity 0.5. Rasterize premultiplied RGBA8 overlays on the producer and composite in place after writing the clean image. Keep single-frame, movie, and replay output consistent. Add overlay, CLI, and queue ownership regressions and document the final output architecture.
183 lines
12 KiB
Markdown
183 lines
12 KiB
Markdown
# GR 4D ray tracing
|
||
|
||
[English](README.md) | **简体中文**
|
||
|
||
一个以物理正确性为优先的离线时空渲染器。项目旨在通过沿四维时空向过去追踪光线,将双黑洞并合等随时间演化的数值相对论模拟渲染为 4K 视频。
|
||
|
||
[](assets/images/schwarzschild_galactic_center.png)
|
||
|
||
*从半径 100 M 处的相机观察 Schwarzschild 时空中的 2MASS 银心方向星场。该参考图像使用 legacy Reinhard tone map(`--tone-map reinhard`)。点击图片查看完整 4K 图像;[渲染命令见下文](#示例schwarzschild-时空中的银心方向星场)。*
|
||
|
||
恒星以独立的星表点源表示,保留方向、温度和振幅。渲染器将它们映射到相机图像中,处理多像、引力透镜放大和频移,再将保留亚像素位置的点扩散函数(PSF)累积到 HDR 图像。电影中的运动相机由世界线与四标架(tetrad)轨迹描述。
|
||
|
||
单张模式在两个 backend 中都支持独立的位置、指向、坐标速度和 roll。例如
|
||
`--observer-position 1.75 0 0 --observer-velocity -0.5 0 0 --look-ra-deg 0 --look-dec-deg 0`
|
||
表示位于史瓦西视界内、向内运动且朝外看的相机,无需借用电影模式。
|
||
参数语义与完整命令见 [单张相机指南](usage.md#single-frame-camera)。
|
||
|
||
## 当前进展
|
||
|
||
当前实现支持解析 **Minkowski** 与 **Schwarzschild** 时空、单张图像、基于观测者轨迹的图像序列、自适应透镜网格,以及可复用的透镜映射文件。程序主要使用 C 编写,通过 OpenMP 实现 CPU 并行;可选的 HIP 后端用于加速 PSF 累积。
|
||
|
||
HIP 保留并行 CPU catalog 映射,并使用由完成事件保护的有界上传缓冲。配置与小规模性能检查见 [HIP 构建说明](build.md#optional-hip-psf-acceleration)。
|
||
|
||
[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 \
|
||
--tone-map reinhard \
|
||
--output output/imgs/summer_triangle.png
|
||
```
|
||
|
||
[](assets/images/summer_triangle.png)
|
||
|
||
*曝光为 `1e12` 的 4K 参考图像;使用 legacy Reinhard tone map(`--tone-map reinhard`)。点击查看完整分辨率。*
|
||
|
||
角度单位为度,`--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 \
|
||
--tone-map reinhard \
|
||
--output output/imgs/schwarzschild_galactic_center.png
|
||
```
|
||
|
||
这里使用更新后的参考图像的渲染设置。`--max-cache-psf-flux 1e8` 允许将明亮 PSF 的翼部截断在缓存半径内,但本次运行没有发生翼部裁剪或 direct fallback。[CPU/HIP benchmark 记录](benchmarks/2mass_galactic_center_cpu_hip_2026-09-07.md)保留了命令、终端输出,以及 CPU/HIP PNG 比特级一致的结果;上述命令省略了可选的 HDR 和 lens-map 导出。
|
||
|
||
上述 Schwarzschild 示例省略位置,因此按指向与半径推导出朝向黑洞的相机。自适应细分默认关闭,应根据所需图像精度配置。tone-mapped PNG/PPM 默认使用逐通道 soft-clip 显示变换(`--tone-map softclip --tone-map-p 2`);`--tone-map reinhard` 恢复上方参考图像使用的历史曲线,线性 HDR FITS 输出不受其影响。可选的有限响应 sensor bloom(`--sensor-bloom-limit E --sensor-bloom-transfer e`,默认关闭)在显示前作用于线性 HDR,且不会改变 FITS 输出。相机控制、图像序列、透镜映射复用、PSF 设置及 HDR 输出参见 [usage.md](usage.md)(英文)。两个可执行文件都可通过 `--help` 查看完整选项。
|
||
|
||
### 示例:紧贴史瓦西视界向外看
|
||
|
||
相机位于 Cartesian Kerr–Schild 坐标 `(2.1, 0, 0)`,紧贴 `r=2M` 的视界外侧
|
||
(`M=1`)。RA=0°、Dec=0° 对应沿 +X 径向向外看;坐标速度为零,表示静态观者,
|
||
而非自由落体相机。这里使用仓库自带的合成测试星表,无需下载巡天数据。
|
||
|
||
```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 \
|
||
--tone-map reinhard \
|
||
--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)
|
||
|
||
*水平视场角 90°、曝光 `0.01`、最大细分级别 3 的 4K 图像;使用 legacy Reinhard tone map(`--tone-map reinhard`)。点击查看完整分辨率。*
|
||
|
||
远方天空集中在朝外方向的有限角域中,多级成像在边缘附近密集堆叠。
|
||
强烈的引力蓝移使 3000 K 和 12000 K 的测试恒星都被推向蓝白色。
|
||
|
||
### 示例:叠加网格的合成测试星表
|
||
|
||
这个示例使用 `assets/sky_grid_5deg.csv` 检查 Schwarzschild 时空中的引力透镜效果与自适应网格细分。主输出是不带网格的成品图;`--draw-mesh` 会额外写出最终的像平面三角网格,因此同一次命令会同时生成 `output/imgs/schwarzschild_test_grid.png`(无网格)和 `output/imgs/schwarzschild_test_grid_mesh.png`(网格叠加)。
|
||
网格在 tone mapping 后以抗锯齿半边叠加。默认采用 Catppuccin Mocha:逃逸为灰色、暗终态为紫色、预算耗尽未决为黄色、真实失败为红色,未追踪为蓝色。颜色与透明度配置详见 `usage.md`。
|
||
|
||
```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 \
|
||
--tone-map reinhard \
|
||
--output output/imgs/schwarzschild_test_grid.png
|
||
```
|
||
|
||
[](assets/images/schwarzschild_test_grid_mesh.png)
|
||
|
||
*4K 测试网格参考图像,展示 `_mesh.png` 网格叠加结果;使用 legacy Reinhard tone map(`--tone-map reinhard`)。点击查看完整分辨率。*
|
||
|
||
### Schwarzschild 自由落体相机轨迹
|
||
|
||
`scripts/schwarzschild_camera_track.py` 生成 movie 使用的 21 列相机 CSV,采用
|
||
入射 Cartesian Kerr–Schild 坐标及 `G=c=M=1`,依赖 Python 3、NumPy、SciPy。
|
||
`--position` 是坐标位置,`--velocity` 是 `dx/dt,dy/dt,dz/dt`,不是局域三速度。
|
||
初始标架由 RA/Dec 与 roll 构造,约定与单张相机一致;省略指向时初始朝向原点。
|
||
也可用 `--tetrad` 提供 16 个按行排列的四标架分量,顺序为 `e0t,e0x,...,e3z`,
|
||
要求正交归一、定向正确,且 `e0` 与指定速度一致。自由落体中费米–沃克输运等同于
|
||
平行输运;初始之后不再强制朝向黑洞。
|
||
|
||
```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
|
||
```
|
||
|
||
脚本的 `--duration` 是持续本征时(单位 M),`--fps` 是每单位本征时的采样数。
|
||
采样为 `tau=k/fps <= duration`,包含初始帧,只在终点恰好满足采样节奏时包含终点;
|
||
10 M、30 fps 共 301 行。`tau` 从零开始,`--t0` 指定初始坐标时间。
|
||
新增 `--movie-track-samples` 让每行恰好对应一帧,保留真实坐标时间,并忽略 renderer
|
||
的 `--start-time/--duration/--fps`;编码时使用生成脚本的 fps。
|
||
不加此选项时原有 movie 仍按坐标时间等间隔采样,不能保持这里的本征时节奏。
|
||
|
||
脚本以解析 metric 导数及 DOP853 联合积分测地线与四标架,默认
|
||
`--rtol 1e-10 --atol 1e-12 --stop-radius 0.001`。轨迹穿过视界继续积分,在该小半径
|
||
数值保护边界停止,报告终止本征时,只保留此前的规则采样;不声称到达精确的 `r=0`。
|
||
可减小半径及误差容限检查收敛。现有 renderer 的光线捕获边界仍为 `r=1.5M`:
|
||
CSV 可以记录更深处的相机,但目前 renderer 会把这些相机发出的光线立即判为捕获。
|
||
脚本报告标架正交归一误差,超过 `1e-6` 时直接报错,不自动修正输运后的标架。
|
||
构建后运行 `python3 tests/test_schwarzschild_camera_track.py`,检查解析径向落体、
|
||
圆轨道及标架输运收敛、非法初值和实际 CSV 渲染。
|