Files
GR-raytracing/video_rendering_plan.md
T

129 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 从单张渲染推进到视频的实现计划
## 目标与边界
把当前已验证的 Minkowski / 解析 Schwarzschild 单张点源渲染器扩展为视频渲染器,同时把顶层执行路径改造成可承受未来 nmesh 四维数据 out-of-core 读取的结构。
视频的物理单位是一个 frame 在相机 coordinate time `t_camera` 的 observer event:位置、四速度和空间 tetrad。每个 frame 的 image-plane samples 都从该 event 向过去追踪 null geodesic。不能用“上一帧的图像平移/变形”替代追踪,也不能把星表变为 RGB sky texture。
本计划的第一项可见产物是带零填充序号的 PNG 序列;视频编码只在 PNG 序列通过测试后作为独立的可选步骤加入。OpenCV 和 FFmpeg 都不进入 `observer`、`geodesic`、`frame` 或 `spacetime` 的物理接口。
## 目标架构
```text
observer-track input
|
v
Movie: frame times + per-frame image meshes
|
v (one refinement generation at a time)
SampleRequest -> RayPool (SoA, inactive / active / terminated)
|
v
time slabs: latest coordinate time -> earliest
activate rays when slab reaches t_camera
advance all active rays to the slab's left boundary
|
v
endpoints installed into the owning frame mesh
|
v
refine if needed; otherwise inverse lens map + catalog + HDR
|
v
numbered PNG frames -> optional FFmpeg video command
```
一个 refinement pass 必须完成一次从最新到最早的 slab sweep 后,才能由 endpoint 判断是否再加样本。下一 pass 只追踪新样本并重新进行 sweep;绝不能在已经释放早期 slab 后临时创建 ray 再回到相机时间。解析 Minkowski / Schwarzschild backend 可以把 `load_slab` 实现为无 I/O 的逻辑 slab,因此能先验证同一 scheduler,而不为解析时空保留逐帧 special path。
## 实施状态(2026-08-27)
本节记录已合入代码和当前 regression 实际覆盖的范围;它不将尚未完成的验收项视作已验证。
| Phase | 状态 | 已落地的范围 | 尚缺的工作 |
| --- | --- | --- | --- |
| A | 基本完成 | canonical 21 列 observer-track CSV、插值、movie frame schedule、编号 PNG/PPM 序列和相关 CLI 已实现。 | 输出仍由 `optics` 写入,尚未拆出计划中的 `output.h/.c`;CSV 非有限数、非单调时间和 PNG 序号冲突的独立回归仍需补齐。 |
| B | 部分完成 | Minkowski 恒 proper-acceleration 轨迹生成器、`0..2`/30 fps/61 frame 基准和前向解析 Doppler regression 已实现。 | 尚无逐 frame 诊断 CSV;a=0 全序列、后向红移、tetrad 正交性/有限差分速度和图像连续性回归仍需补齐。 |
| C | 核心路径完成,验收未完成 | `MetricSlab` 接口、SoA `RayPool`、slab 到达时的 lazy ray initialization、倒序 slab sweep、OpenMP 批量推进和 `(frame_id, vertex_id)` endpoint 回填已实现。 | 仍未 compact terminated rays 或支持 RayPool 增长;未记录/测试每 generation 每 slab 一次 load/free;scheduler 与 wrapper 的完整 endpoint/image 对比尚未成为当前测试。 |
| D | 部分完成 | 多代 request/probe mesh、最长边二分、共享边 conforming 闭包、相对+绝对天空方向误差、capture/escape 边界细分,以及单帧/movie 共用 generation 调度已实现。 | nmesh slab I/O/ghost-slice/memory contract、slab instrumentation 和强透镜收敛基准仍未完成。 |
| E | 未开始 | 仅有静态 Schwarzschild 单帧和局部 inward boost。 | `30M -> 20M -> 30M` observer track、movie regression 和连续性检查。 |
| F | 未开始 | PNG sequence 是默认 movie 输出。 | FFmpeg 编码命令/目标、解码核验和可选 direct-video backend。 |
当前 `make test` 覆盖 geodesic、frame、Schwarzschild、observer-track/movie 和 catalog prefetch;通过不等价于上述未覆盖验收项已经满足。
## Phase A:先建立输入与输出边界,保持单帧兼容(基本完成)
1. 新增 `observer_track.h/.c`,将目前的 `ObserverState` 提升为可插值的 `ObserverTrack`:每个 sample 保存 `t_coordinate`、`tau`、`x[3]` 和完整 tetrad。提供加载、严格单调时间校验、区间查找、插值和销毁函数。原有固定 observer 构造函数保留,作为只含一个 sample 的兼容快捷方式。
2. 第一版轨迹输入采用人可审阅的 21 列 CSV,字段固定为 `t,tau,x,y,z,e0t,e0x,...,e3z`;不在 renderer 内从“速度曲线”临时猜 tetrad。loader 做完整性、有限数与严格单调时间检查;tetrad 的 metric 正交归一由轨迹生成器和 backend-aware regression 验证。另提供生成器工具/模式为测试写出 CSV。这样 NR 生产轨迹、解析测试轨迹和以后离线 trajectory generator 使用完全相同的 renderer 输入。
3. 加入 `movie.h/.c`,定义 `MovieSettings`、`MovieFrame`(`frame_id`、`t_camera`、插值得到的 observer state、mesh、HDR image)与 `Movie`。用 `start-time`、`duration`、`fps` 生成 frame 时间表;先拒绝轨迹覆盖范围外的时间。
4. 将 `render_frame()` 中与单帧无关的工作拆成“初始化 mesh / 安装 endpoint / splat HDR / 写出”四个明确步骤。默认构建写 PNG;未启用 libpng 时单帧和 movie 序列统一退回 PPM。movie 模式只是调用同一套 frame rendering 与 optics。
5. 新增 `output.h/.c`,从 `optics` 移出文件命名和写图逻辑。默认 movie PNG 仍复用当前 libpng 路径,命名固定为 `<output-dir>/<prefix>_%06u.png`,例如 `output/imgs/minkowski_accel_000042.png`;无 libpng 的 PPM fallback 只替换扩展名。创建前验证目录、prefix 与帧号范围,写入失败应指出 frame id 和路径。
验收:原有 `make test` 和两种单帧 backend 的输出保持不变;新测试验证 CSV 拒绝缺列、非有限数与非单调时间,frame 时间表精确包含首帧且不越界,PNG 序号无冲突。此阶段不要求 FFmpeg,也不改变 ray tracing 的调度方式。
## Phase B:用平直时空 accelerated observer 验证 video / tetrad / Doppler(部分完成)
1. 为 Minkowski 增加“从静止开始、沿相机 forward 轴恒定 proper acceleration”的离线轨迹生成器,且把生成的 samples 写成上述通用 CSV。取初始 event `t=tau=0, x=0`,加速度方向为 forward;以 proper time 参数化:
\[
\eta=a\tau,\quad t=a^{-1}\sinh\eta,\quad x_\parallel=a^{-1}(\cosh\eta-1),
\]
`e_(0)` 与 forward tetrad 为相同 rapidity `eta` 的 Lorentz boost,其余两根空间轴不变。用 `t` 作为 frame / ray / future slab 的共同时间轴,`tau` 只作轨迹元数据。首个固定 regression 使用 coordinate-time `0..2`、30 fps(含两端共 61 frame)以及 `a = 1.52`(`c=1`);末帧速度约为 `0.95c`,足以产生清晰的 aberration、headlight 与 Doppler 效应。CLI/配置仍可覆盖这些基准值。
2. movie 的首个可运行实现可先在每 frame 调用当前 `geodesic_trace_past`,以尽快验证轨迹和输出链;但它只能作为解析 backend 的过渡测试模式。紧接着在同一 phase 完成 Phase C 的 RayPool/slab scheduler,并删除 movie 路径中的逐帧 trace loop。单帧入口仍可直接 trace,便于 debug。
3. 对每个 frame 保存可机器检查的诊断:中心方向的 `g`、前向与后向指定 catalog stars 的 `g`、它们的 image position / flux,以及 observer rapidity。诊断是 CSV/测试数据,不叠加到图像。
4. 回归物理:`a=0` 时所有 frame 与静止 Minkowski 基准一致,且 `g=1`;加速后前半球出现 aberration/headlight 集中,前向星蓝移、后向星红移,结果与解析 Doppler factor 逐 sample 比较。再检查 tetrad 的 Minkowski 正交归一和 `e_(0)` 与轨迹有限差分速度的一致性。
验收:短序列(低分辨率、几十帧)能快速写出 PNG;首尾帧和诊断共同证明从静止到加速的连续变化,没有镜头翻转、时间倒退或每帧亮度无物理原因的跳变。
## Phase C:以真正的 time-slab scheduler 替换 movie 逐帧追踪(核心路径完成,验收未完成)
1. 扩展 `spacetime.h` 为 slab-oriented 接口:source 打开/重置、查询可用时间范围、从 `t_hi` 装载前一个 `MetricSlab`、释放 slab、在 slab 内 `eval` / `classify`。解析 backend 的 slab 是轻量边界对象;nmesh 才在此处进行顺序 I/O。顶层 `movie` 不得检查 backend 类型。
2. 新增 `ray.h/.c` 的 SoA `RayPool`。字段至少包含 coordinate time、位置、`Pi_i`、`log(alpha p^0)`、step size、`frame_id`、mesh vertex/sample id 与状态;capacity 可增长但不逐 ray 分配。所有 endpoint 写回使用稳定的 `(frame_id, vertex_id)` 关联。
3. 将 geodesic 拆为“从 observer 初始化 ray”“在指定 slab 内推进到左边界或终止”“提取 endpoint”。保留现有 `geodesic_trace_past` 作为单帧/测试 convenience wrapper,以免破坏已有 regression。
4. 每个 generation 的调度严格为:收集所有 frame 尚未追踪的 mesh vertices -> 建 RayPool -> 从 movie 最大 `t_camera` 倒扫 -> 在相应 slab 激活 rays -> OpenMP bulk evolve active rays -> compact terminated rays -> 释放 slab -> 安装结果。所有后端可变 evaluator scratch 放在每线程 workspace;不使用 per-ray task 或 mutex。
5. 在现有固定 coarse mesh 上先完成以上路径,保持当前“image vertices -> source triangles -> catalog inverse interpolation -> PSF”的数据流和共享边界 ownership。adaptive refinement 留作下一 phase;不能为视频退化成逐 pixel sky lookup。
验收:对同一 Minkowski 与解析 Schwarzschild observer track,slab scheduler 与旧逐帧 convenience path 的 endpoint status、`n_infinity`、`log g` 及完成图像在容差内一致;增加 instrumentation 证明一个 generation 的每个 slab 只 load/free 一次,而不是每 frame 一次。Minkowski / Schwarzschild 不应出现额外磁盘 I/O。
## Phase D:补全多 pass adaptive mesh 与 out-of-core 准备(未开始)
1. `FrameLensMesh` 采用 append-only stable vertex ID、generation-local request/probe 队列、triangle level 与“缺失 endpoint”状态。每 pass 的 probe 只放在最长 image-plane 边中点;完整 sweep 后才安装 endpoint 并改变拓扑。细分保留同时超过绝对与相对 `n_infinity` 方向误差阈值的几何判据,并受最大层数、最小长边和最小面积约束;capture/escape 不一致强制细分。另以三顶点的有向球面面积比 `J = Omega_source / Omega_image` 检测 fold:仅当共享边两侧非零 `J` 异号,且 `min(abs(J_left), abs(J_right))` 小于阈值时,细分该共享边的两叶;负 parity 本身保留而不剔除。
2. 以迭代 queue(可按 frame/root tile 并行、线程本地 request buffer 后 sort/deduplicate)替代递归 task。每一个 pass 完整执行 Phase C sweep;只有所有 frame 都无新请求才进行 catalog splat。
3. 在 movie 生命周期中及时释放已完成的 RayPool、临时 request 和单帧 HDR;保留最终 mesh/endpoints,或在渲染 PNG 后按明确策略释放,避免视频时无界增长。
4. 为 nmesh 预留并实现 source-side slab overlap / temporal ghost-slice 契约、可配置 memory budget、slab coverage 日志和线程本地 `MetricWorkspace` ownership。此 phase 不重采样为 Cartesian grid,也不假定相邻时间 slice 的 AMR tree 相同。
验收:构造可控 Schwarzschild strong-lensing case,确认 refinement 只增加必要 samples、多个 image patches 正确产生多像、shared edge 上的星不会重复 splat。记录每 pass 的 ray 数、峰值 active ray 数、slab load 数、peak metric memory 与 wall time,作为未来 nmesh 性能基线。
## Phase E:动态 Schwarzschild 视频验证(未开始)
1. 首先使用解析 Schwarzschild Kerr--Schild backend 和离线 observer track,不改变 metric 为静态这一事实。首个回归轨迹人为规定为:从静止于 `r=30M` 出发,平滑加速径向向内,到 `r=20M` 附近平滑制动为静止,再按时间反演的同一路径返回 `r=30M`;径向局部速度上限取 `0.5c`(相对每个 event 的 static Schwarzschild tetrad)。轨迹生成器必须同时积分/构造位置和正交 tetrad,而非只对当前 `observer_inward_speed` 逐帧套 boost。
2. 这条路线远离 horizon,优先测试运动频移、shadow / lensing 的连续形变和回程可逆性;CSV metadata 标注 `prescribed_radial_turnaround`、速度上限与 proper acceleration。renderer 不对其物理来源作假设。逼近 horizon 的路线留到该基准稳定后再加。
3. 对每帧测试 shadow 轮廓、Einstein ring / 多像位置、capture fraction、`g` map 与 catalog star temperature shift 的连续性。与同一时刻旧单帧结果比对;再以静止轨迹确认它退化为现有 Schwarzschild baseline。
验收:前进与后退均显示相对静止 observer 的引力/运动频移和相应 image distortion,且不会因 frame 边界、slab 边界或 tetrad 插值出现闪烁。这里只要求定性图像和定量 ray regressions;具体径向轨迹参数、ODE step、refinement 阈值仍由收敛试验决定。
## Phase F:输出视频与运行界面(未开始)
1. 保持 PNG sequence 为默认调试/测试产物:任何失败都能定位到具体 frame,也便于逐帧回归与检查 tone mapping。CLI 采用 `--frames-dir`、`--frames-prefix`、`--start-time`、`--duration`、`--fps`、`--observer-track`;单帧 `--output` 继续存在且语义不变。
2. 在 PNG 序列稳定后,添加 `make encode` 或单独的 documented FFmpeg invocation,把序列编码为 H.264/H.265/ProRes 等明确选择的容器。编码读取已经 tone-mapped 的 PNG;HDR/EXR 与最终色彩管理是后续独立决策,不悄悄混入首次视频实现。
3. 如需“直接输出视频”,实现一个只属于 `output` 的 FFmpeg pipe/encoder backend,并以同一 RGB frame bytes 与帧率接口接收图像。它必须与 PNG 逐帧输出并列、可独立关闭;第一次实现优先用 FFmpeg CLI/library,不强制引入 OpenCV。只有当 OpenCV 未来提供明确的读取/验证价值时才加入,避免让其成为核心依赖。
验收:同一短 PNG 序列可被 FFmpeg 无丢帧编码;解码后帧数、分辨率、帧率与原序列一致。PNG 写出失败或编码器不可用不能影响 tracing 结果的正确性,错误信息应给出可重跑的 PNG 序列位置。
## 后续提交与测试顺序
1. 补齐 A--C 尚缺验收:输入边界、逐帧 Doppler 诊断、scheduler 对比和 slab instrumentation。
2. `multi-pass adaptive refinement`。
3. `Schwarzschild moving observer regressions`。
4. `FFmpeg encoding backend / documentation`。
5. `nmesh 4D slab reader`,用数值 Schwarzschild 对解析结果作 regression,最后才接 FOZ4c BBH。
每一步均应保留前一步的 Minkowski 和 Schwarzschild regression;新参数(轨迹采样密度、slab 内存预算、ODE step、refinement 阈值、PNG/视频 tone map)由小型 prototype 或收敛测试选择,而非在本计划中固定。
## 已确认的首批基准
1. observer track 采用上述 21 列完整 CSV;之后若 NR trajectory 有既定格式,再由独立转换器生成该 canonical CSV。
2. Minkowski 采用两秒、从静止持续加速到约 `0.95c` 的基准序列,验证前灯效应与前向蓝移。
3. Schwarzschild 首先采用 `30M -> 20M -> 30M`、局部径向速度上限 `0.5c` 的人为平滑进退轨迹;它是 renderer input 的测试数据,不应被误认为自由落体解。