geopro/docs/superpowers/specs/2026-06-26-gpr-3d-render-pe...

211 lines
16 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

# GPR 多通道三维体渲染性能问题 — 分析文档(供外部专家评审)
> 自包含技术文档。读者无需了解本代码库内部,只需具备 GPU 体绘制 / VTK 基础。
> 目的:把"探地雷达(GPR)多通道阵列数据渲成可交互三维体"遇到的性能问题、已试方案、实测数据、
> 待定关键点完整呈现,供外部专家判断方向。
---
## 1. 背景与系统
- 桌面端 C++ 应用Qt6 + **VTK 9.6.2**),渲染探地雷达(GPR)采集的地下三维数据,要求**可交互**(旋转/缩放)。
- 渲染用 VTK 的 `vtkGPUVolumeRayCastMapper`OpenGL GPU 光线投射体绘制)。
- 当前测试机 GPU32 个着色器纹理单元(典型独显/中端)。
## 2. 数据特征(关键,决定一切)
多通道阵列 GPR一次采集一条"测线(line)"
- **道(trace)**:一个位置一根天线的垂直回波,深度方向 **821 采样**
- **通道(channel)**:阵列横向并排的多对天线,本数据 **14 通道****相邻通道横向间距 ≈ 10.5cm**(来自 `.ord` 文件真实偏移 -0.686…+0.686m,跨度 1.37m)。
- **沿测线道间距 ≈ 4.9cm**(比横向通道间距细 ~2 倍)。
- 一条测线:沿路 **~45305 道**,覆盖 **~2.2km**(一条南北向道路)。
- **共 20 条测线 = 同一条路来回扫 20 趟**(车载,每趟阵列覆盖约 1.4m 宽,多趟铺横向)。
**单条线 = 一个三维体**X=沿测线(~45305)、Y=通道(14)、Z=深度(821)。
**关键业务约束(来自现场专家)**
- 通道太稀10.5cm)→ 需**线内通道间插值**加密(相邻真实天线之间插,物理成立);
- **绝不做"测线之间"的插值**(车与车之间是真实物理空隙,插出来"信号全是假的",工程上不可接受);
- 多条测线"分开各自插值,渲染可以合到一起"。
GPR 数据的统计特征(实测,见 §6**~91% 体素近零(反射层之间是空的),但反射层横贯整个深度分布**(不是集中一坨)。
## 3. 已建成并验证可用的功能(不是问题所在)
1. **线内通道插值**:读 `.ord` 真实横向偏移,规则化到 2.5cm 网格、相邻通道线性插值(不跨线)。
实测 Y 由 14 加密到 **56**。有单元测试。
2. **多体单遍合成**20 条独立体(各自插值)作为一个 `vtkGPUVolumeRayCastMapper` 的多个端口注册进
`vtkMultiVolume`**单遍 ray-cast 合成**(而非每条体一遍)。已验证。
3. **纹理单元上限自动退避**:单个 multi-volume 同时挂的体数受 GPU 每着色器纹理单元上限制约
(每体约吃 4 个单元 → 32 单元机上**一个包最多 7 体**,第 8 体报错并丢体)。已实现"渲一帧→报错则
每包减 1 重建重渲"的自动退避(强制 K=12 → 自动退避到 7无丢体
4. **运行时换贴图边界**(确定性测试结论):给某端口**就地换贴图**——若**保持包围盒不变**(同范围、
只改 Y 密度)则 multi-volume 算得对;若**改包围盒**任意子区域、origin/范围/spacing 变)则破坏
其缓存 `TexToBBox` → 体断开/消失。
5. 通道维 LOD、统一传函、色标图例等。
## 4. 核心问题:性能
- **20 条密体Y=56总览交互极卡**:静止 ~1.7 fps旋转/缩放掉到 < 1 fpsGPU 100%)。
- 渲染**视觉正确**雷达剖面纹理清晰横向连续合成无误纯属性能
- 现有提速手段都是**"交互时降质"**方向降屏幕分辨率加粗采样步长)——**损可见质量**治标
用户明确要求"有没有不损可见质量的根本性提速业界最佳实践"
## 5. 已分析/已试的所有方案(含理由与状态)
| # | 方案 | 理由 | 状态 / 结论 |
|---|---|---|---|
| A | multi-volume 单遍合成 | "N =N ray-cast"降到分包遍数 | 已实现但单遍内每步仍要在重叠体里逐个采样 |
| B | 纹理单元自动退避分包 | 绕开 GPU 纹理单元上限不丢体 | 已实现K=7/包20 =3 )。代价**跨包重叠合成不正确接缝** |
| C | 交互降屏幕采样(ImageSampleDistance) | VTK AutoAdjust 标准手段 | 已做。**损质量** AutoAdjust 只降屏幕不降沿光线步长 |
| D | 交互手动加粗沿光线步长(SampleDistance) | 通道插值后 Y 自动步长极细巨卡这才是大头 | 已实现`--sampleDist`/`--dragSampleMul`)。**损质量且用户尚未实测** §7 待定 |
| E | 通道维 LOD远疏近密换 Y 平面子集| 保包围盒换贴图#4 验证安全 | 已实现**只减纹理内存不减每步重叠体采样次数 对此瓶颈几乎无效** |
| F | **装箱单体(binning)**各线先逐线插值再把**真实道**摆进一个总览网格体空隙透明不跨线插值| 一个体一遍每步采 1 ~20×真实数据无假信号 | 技术可行合规**用户否决**装箱合并后**总览里分不出各线**而用户要"一起渲染时仍能逐线区分/查看"→ 合并即失去意义 |
| G | **空体素跳过 ESS换 OSPRay/ANARI 后端)**跳过透明背景块 | 业界对稀疏体的头号提速不损质量 | **实测对本数据收益有限** §6保质量阈值下仅 ~2×**ESS 跳的是空区不解决"重叠"**。VTK 库存 mapper 无自动 ESSOSPRay 本环境未编vcpkg 无包 |
| H | 减少同屏体数只渲选中 7 | 真实工作流本就是选几条1 1 | 免费永远有效使用方式非技术 |
## 6. 关键实测数据
### 6.1 ESS空体素跳过潜力——零依赖实测决定要不要上 OSPRay
对一条真实测线密体5702×56×789按块算 min/max统计"整块落在近零透明带"的占比=ESS 可跳块
| 透明带半宽(相对半值域) | 8³ 块可跳占比 | 理论提速上限 1/(1占比) | 说明 |
|---|---|---|---|
| 5% | 8% | 1.1× | 极保守 |
| **10%(保质量,不丢弱反射)** | **52%** | **~2.1×** | |
| 20% | 80% | ~4.9× | 开始把弱反射当背景丢 |
| 30%激进| 90% | ~10× | 明显损质量 |
- 体素层面 **91% 近零**但块层面ESS 实际粒度保质量阈值下**只能跳 ~52% 理论 ~2×**。
- 原因**反射层横贯整个深度分布**多数块里总混着信号跳不掉 10× 须用激进阈值损质量)。
- **更关键**ESS "空区"**不减少"重叠"**——在有信号的块里仍要逐个采样所有重叠体
### 6.2 其它实测
- multi-volume 纹理单元上限本机 7 /32 单元 8 体报 "Hardware does not support the number of textures"。
- 体维度示例coarse 4 ~11000×56×793/线coarse 32 ~1400×56×780/线
- 20 densecoarse 32底图 level 0Y=56、分 3 **渲染正确**交互 ~1.7fps**未加 D 方案的旧构建**)。
## 7. 关键点——已实测,结论修正(原假设两条都被推翻)
### 7.1 "重叠几层"——实测:**平均 ~8.7 层、最大 15 层(不是 ~23也不是 20**
纯几何测各线世界 AABB 投到 X-Y 俯视 footprint细网格统计每格覆盖层数`--overlapStat`
- footprint横向 X37m沿路 Y2.2km
- **有体覆盖处平均重叠 8.74 最大 15 **穿 1214 个体的格子占 ~42%。
- **结论修正**"~23 "假设****开发团队和外部专家都猜偏了**重叠是真实的大瓶颈**。
- **且这 9 层是冗余**20 趟是同一条路反复扫同一地下点被测了 ~9 9 个重叠体在该处**都非空**
同一地下结构)→ **ESS 在重叠区一个都跳不掉**再次印证 ESS 不解决重叠)。
### 7.2 "采样 vs 重叠谁是大头"——实测:**采样瓶颈fps 线性正比于步长**
20 条密体静止近景离屏步长越大越快越糙
| sampleDist | fps | 相对 |
|---|---|---|
| 0.2(≈自动细| 1.3 | 1× |
| 0.5 | 3.2 | 2.5× |
| 1.0 | 5.9 | 4.5× |
| 2.0 | 11.3 | 8.7× |
| 4.0 | 20.9 | 16× |
- **步长翻倍fps 翻倍 GPU 是采样瓶颈**。总开销 光线数 × (光线长/步长) × ~9 个重叠体
- D 方案手动步长**确实直接强力提速****保质量的步长(≈ Nyquist0.5×体素下仍只 ~2 fps**
——因为 **9× 冗余重叠**把它乘了回去要到交互级(10+fps) 得把步长粗到 ~2.0欠采样 Z 薄层)。
### 7.3 合并诊断(两测合起来)
**= 采样密度 × ~9 倍冗余重叠两者都真实。**
- D 方案(粗化采样)提速强但保质量步长下被 9× 重叠压回 ~2fps要交互须损质量
- **唯一"保质量又快"是去掉那 9× 冗余重叠**同路重扫的同一地下点合并/装箱取真实道不跨线
插值)→ 一个体一遍 ~9× 提速 Nyquist 步长下也能交互、**零质量损失**冗余测量本就该合并降噪)。
- **但这与用户"保持 20 条可区分"直接冲突**——而这 9 层在物理上是**冗余测量**同一地下结构扫了 9
保持它们"可区分"的工程价值存疑
### 7.4 CPU OSPRay vs GPU仍未测
ESS 对本数据 ~2× 且不解决 9× 重叠OSPRay 主要 CPU对手是 GPU 数千核。**很可能换 OSPRay 比现状还慢**
且为 ~2× 重编整个 VTK 投入产出极差不建议在去掉冗余重叠之前考虑
### 7.5 "多线为何卡"的根因确诊passcost决定架构——结论**不是固定开销,是没用 LOD**
> 背景:最初 P11/P12 是"各线独立 mapper + 视野 LOD",实测仍 0.5fps。需确诊卡在三个嫌疑哪个:
> ①LOD 选区没削小 ②N 遍固定开销 ③重叠没摊掉。`passcost` 命令N 个独立 GPU mapper 各渲一个 64³ 小体
> (模拟 LOD 削过的小区),分"铺开/不重叠"与"叠在一起/重叠",测离屏稳态 fps vs N。
| N | 铺开(不重叠) fps | 叠加(重叠) fps |
|---|---|---|
| 1 | 177 | 204 |
| 5 | 162 | 43 |
| 10 | 144 | 22 |
| **20** | **78** | **11** |
**判读(决定性):**
- **嫌疑 ②(N 遍固定开销排除**20 个独立 mapper 铺开仍 **78fps**17778远非线性)。
**各线独立 mapper 架构上完全可行,固定开销温和。"multi-volume 单遍 ⊥ 视野 LOD"这个不可兼得不致命**——
放弃单遍回独立 mapper 并不慢
- **嫌疑 ③(重叠真实但小体下可控**叠加随 N ~1/N每条光线乘 N **20 层 64³ 叠加仍 11fps**可用
再叠屏幕降采样更快
- **嫌疑 ①(选区没削小= 真凶**passcost 小体 20 层叠加=11fps而真实 view-all 1.7fps——差距全在
**贴图大小**当前渲的是**整卷底图**~11000×56×200 上亿体素/**根本没用视野 LOD 把它削成小区**。
这是**最好结局可修不动地基只需真正用上 LOD**。
**对架构的直接含义**本会话引入的 **multi-volume 单遍是错误取舍**——"单遍"关掉了 LOD改固定整卷贴图
导致大贴图 × 9 层重叠 = 1.7fps。而 passcost 证明独立 mapper 够快**根本不必为单遍牺牲 LOD**。
## 8. 部署约束(硬件不确定,跨厂商)
客户机配置未知可能无独显 N卡/A卡/Intel)。**没有任何单一渲染器能在 N 卡和 A 卡上都做"GPU+ESS"**——
GPU 体光追渲染器全厂商锁定N NVIDIA VisRTX/OptiX/IndeXIntelOSPRay-GPUA 基本无成熟方案)。
跨厂商唯一通用的是 **OSPRay-CPU免显卡、任意 x86** **OpenGL任意 GPU、但无 ESS=现状)**
若上多后端"OSPRay-CPU 保底 + 探测到 N卡/Intel独显时升对应 GPU 后端 + OpenGL 终极兜底"。
## 9. 关键问题——大多已被实测回答
1. ~~有没有不损质量的根本性提速法~~ **有且是通用解LOD视野自适应多分辨率**—— GPU 单帧实际
ray-cast 的体素量**与数据总量解耦只与"屏幕能看清的量"挂钩**Task 12c 单体已验证 752/380fps)。
§7.5 passcost 证明它**对多线也成立**独立 mapper 开销温和20 条铺开 78fps)。
2. ~~"卡"的主因~~ **已确诊§7.5):不是 N 遍固定开销(排除),是【当前根本没用 LOD、渲整卷大贴图】嫌疑①。**
本会话引入的 multi-volume 单遍为"单遍"关掉了 LOD 大贴图 × 9 层重叠 1.7fps
3. **9 层重叠的正确定位**外部专家纠偏 + passcost 印证它只是**这批数据同路重扫 20 的特例倍数**
**不是渲染本质问题**本质是"单帧采样量 > GPU 吞吐",通用解是 LOD扛任意大数据无重叠但更大也能扛
9 层重叠在 LOD 之上降级为"一个被摊薄的常数因子"passcost20 层小体叠加仍 11fps
**不要让渲染架构围绕这个特例设计。**
4. ESS/OSPRay/多后端:**继续埋掉**——ESS 对本数据 ~2× 且不解决重叠、CPU 对手是 GPU且**它解决的是 LOD
已经解决的通用问题**,投入产出差。
## 10. 最终结论passcost 确诊后,架构清晰)
- **渲染架构 = LOD 中心(视野自适应、单帧量与总量解耦)。** 这是扛"任意大数据"的通用根本解,
Task 12c 单体已验证、§7.5 passcost 多线也成立。
- **本会话的 multi-volume 单遍是错误取舍**:为"单遍合成"牺牲了 LOD、改固定整卷大贴图正是当前 1.7fps 的
直接原因。passcost 证明独立 mapper 开销温和20 条 78fps**根本不必为单遍弃 LOD**
- **正解 = 各线独立 mapper + 视野 LOD逐线用 Task 12c 引擎)+ 停手才重建**(不每帧重建,避免 P11/P12
那种"20 条每帧重建上传"的 thrash——那才是 0.5fps 的另一半原因,与稳态 ray-cast 无关,已被 P13 思路解决)。
让每条线只渲视野内小区 → 即使 9 层叠加也可用。
- **9 层重叠 = LOD 之上的可选应用层优化**(对同路重扫冗余可"合并/降噪",顺带省 9×**不进渲染地基**。
用户要逐条区分就不合并(靠 LOD 摊薄),要纯总览就合并。
- **采样步长D 方案)= LOD 框架内的质量旋钮**,非独立根本解。
- **ESS/OSPRay/多后端:不做**(不解决 LOD 已解决的通用问题,对本数据收益差)。
**下一步(确诊已完成,可开工)**:把多线总览从"multi-volume 单遍固定整卷"改回"各线独立 mapper +
视野 LOD + 停手重建",让单帧渲染量随视野走、与 20 条总量解耦;实测多线总览是否达交互级。
这是顺着通用 LOD 框架、被 passcost 数据支撑的明确方向——不再围着 9 层重叠这个特例转。
---
### 附:相关已落地代码 / 诊断工具(如专家要复现)
- 通道插值:`src/io/gpr/GprGeometry.cpp::planChannelInterpolation` + `Gpr3dvVolumeBridge.cpp`
- 多体合成/退避/质量控制/通道 LOD`tools/gpr_poc/main.cpp::cmdViewAll`
- **诊断命令**`tools/gpr_poc/main.cpp`,可直接跑复现 §6/§7 的数):
- `gpr_poc ess-stat <dir> <line>`ESS 空块潜力§6.1
- `gpr_poc view-all <dir> <gps> --overlapStat`实测重叠层数§7.1
- `gpr_poc view-all <dir> <gps> --sampleDist D`步长↔fps§7.2
- `gpr_poc passcost --size 64 --overlap 0|1`N 遍开销 vs 重叠 隔离测§7.5
- 数据/插值口径 spec`docs/superpowers/specs/2026-06-25-gpr-line-channel-interpolation-and-multivolume.md`
- 多后端 ESS 架构 spec**结论:不做,见本文 §10**`docs/superpowers/specs/2026-06-26-gpr-multibackend-ess-rendering.md`
---
## 摘要(一页结论,供决策)
1. **现象**20 条通道插值密体总览,~1.7fps、交互更卡。视觉正确,纯性能。
2. **确诊**passcost 隔离测):**不是 N 遍固定开销**20 独立 mapper 铺开 78fps排除
是**当前根本没用视野 LOD、在渲整卷大贴图**× 9 层重叠)。本会话的 multi-volume 单遍为"单遍"
牺牲了 LOD是直接原因。
3. **通用根本解 = LOD**单帧渲染量与数据总量解耦扛任意大数据Task 12c 单体 752fps、passcost 多线
也成立。9 层重叠只是**本批数据的特例倍数**,是 LOD 之上一个可摊薄/可选合并的因子,**不是架构核心**。
4. **正解**:各线独立 mapper + 视野 LOD + 停手才重建(弃 multi-volume 单遍)。
5. **明确否定**ESS/OSPRay/多后端(对本数据 ~2×、不解决重叠、解决的是 LOD 已解决的通用问题)。