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

16 KiB
Raw Permalink Blame History

GPR 多通道三维体渲染性能问题 — 分析文档(供外部专家评审)

自包含技术文档。读者无需了解本代码库内部,只需具备 GPU 体绘制 / VTK 基础。 目的:把"探地雷达(GPR)多通道阵列数据渲成可交互三维体"遇到的性能问题、已试方案、实测数据、 待定关键点完整呈现,供外部专家判断方向。


1. 背景与系统

  • 桌面端 C++ 应用Qt6 + VTK 9.6.2),渲染探地雷达(GPR)采集的地下三维数据,要求可交互(旋转/缩放)。
  • 渲染用 VTK 的 vtkGPUVolumeRayCastMapperOpenGL 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 0、Y=56、分 3 包,渲染正确;交互 ~1.7fps未加 D 方案的旧构建)。

7. 关键点——已实测,结论修正(原假设两条都被推翻)

7.1 "重叠几层"——实测:平均 ~8.7 层、最大 15 层(不是 ~23也不是 20

纯几何测(各线世界 AABB 投到 X-Y 俯视 footprint、细网格统计每格覆盖层数--overlapStat

  • footprint横向 X≈37m、沿路 Y≈2.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 铺开仍 78fps177→78远非线性。 → 各线独立 mapper 架构上完全可行,固定开销温和。"multi-volume 单遍 ⊥ 视野 LOD"这个不可兼得不致命—— 放弃单遍、回独立 mapper 并不慢。
  • 嫌疑 ③(重叠)真实但小体下可控:叠加随 N ~1/N每条光线乘 N20 层 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/IndeXIntel→OSPRay-GPUA 卡→基本无成熟方案)。 跨厂商唯一通用的是 OSPRay-CPU免显卡、任意 x86OpenGL任意 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
  • 多体合成/退避/质量控制/通道 LODtools/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|1N 遍开销 vs 重叠 隔离测§7.5
  • 数据/插值口径 specdocs/superpowers/specs/2026-06-25-gpr-line-channel-interpolation-and-multivolume.md
  • 多后端 ESS 架构 spec结论:不做,见本文 §10docs/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 已解决的通用问题)。