Files
XCEngine/docs/used/3DGS渲染路径对齐参考实现修复计划_过期归档_2026-04-12.md

8.4 KiB
Raw Blame History

3DGS 渲染路径对齐参考实现修复计划

日期2026-04-11

1. 文档定位

旧计划《3DGS渲染集成测试与Renderer正式接入计划》已经完成了主体接入工作

  1. GaussianSplat 资源链路已经打通
  2. GaussianSplatRendererComponent / VisibleGaussianSplatItem / BuiltinGaussianSplatPass 已经落地
  3. tests/Rendering/integration/gaussian_splat_scene 已经建立

当前剩下的不是“是否接进 Renderer”而是“当前 Renderer 中的 3DGS 正式路径与参考实现仍有关键偏差,导致画面结果错误”。
因此这份新计划只聚焦当前的渲染正确性修复与测试收口,不再重复旧计划里已经完成的接入事项。

2. 已确认的根因

这轮问题已经不是相机摆放、PLY 导入或简单参数调节问题,而是渲染路径本身与参考实现不一致。

2.1 当前引擎缺少正式的 accumulation + composite 两段式路径

参考实现的关键流程是:

  1. 先把 splat 绘制到单独的半浮点累积 RT
  2. splat draw 使用前向累积专用 blend
  3. 最后再把累积 RT composite 回主场景颜色缓冲

参考位置:

  1. mvs/3DGS-Unity/Shaders/RenderGaussianSplats.shader
  2. mvs/3DGS-Unity/Shaders/GaussianComposite.shader
  3. mvs/3DGS-Unity/Runtime/GaussianSplatRenderer.cs

当前引擎却是:

  1. engine/assets/builtin/shaders/gaussian-splat.shader 中直接输出到主场景颜色
  2. BuiltinGaussianSplatPass 直接把 camera color attachment 作为 render target
  3. 虽然 BuiltinGaussianSplatPassResources 已经有 AccumulationSurface 抽象,但执行路径没有真正使用它

这说明当前实现是“资源抽象已经开始正式化,但执行流仍停在临时路径上”,这是第一根因。

2.2 当前排序方向与当前 blend 方程不匹配

当前引擎:

  1. PrepareOrder 阶段使用相机空间 viewCenter.z 作为排序距离
  2. bitonic 结果本质上是按升序排列
  3. draw shader 却使用普通透明混合 Blend SrcAlpha OneMinusSrcAlpha

如果保留当前普通透明混合,就应当使用严格的 back-to-front 语义;
如果要对齐参考实现的 front-to-back 累积,就必须同时切到参考的累积 blend 与独立 accumulation target。

也就是说,当前并不是“排序可能有一点不准”,而是“排序约定与 blend 合约本身冲突”。

2.3 当前测试参数只是在放大问题,不是问题本体

当前集成测试里:

  1. 只取了 65536 个 splat 子集
  2. _PointScale = 3.0
  3. 最终输出直接落在主 backbuffer

这些会让错误更明显,但不会单独制造当前这种大面积拖影、糊片、黑色尖刺。
真正的问题仍然是 draw/composite 路径设计错误。

3. 本轮修复目标

本轮只做一件事:把当前引擎中的 3DGS 渲染主链,彻底对齐到参考实现所依赖的那组最小正确语义。

具体目标:

  1. 建立正式的 accumulation render target
  2. draw shader 改为服务 accumulation 的输出与 blend 合约
  3. 新增正式的 composite pass把 accumulation 结果混回主场景
  4. 统一排序方向与 blend 语义,不允许继续“排序一套、混合一套”
  5. 保证 gaussian_splat_scene 在 D3D12 / Vulkan / OpenGL 三后端下都能稳定回归

4. 非目标

这轮明确不做:

  1. 不接 editor 中的 3DGS 显示与交互
  2. 不做 selection / cutout / 编辑工具链
  3. 不做 3DGS 的 streaming / LOD / chunk 级高级优化
  4. 不在这轮重做 GaussianSplat artifact schema
  5. 不引入 compute shader 之外的新渲染架构分支

5. 执行原则

5.1 先对齐正确性,再谈进一步优化

这轮优先级必须是:

  1. 先把“渲染方程”和“执行路径”对齐
  2. 先让集成测试输出正确
  3. 再考虑性能、压缩、子集规模、排序频率等问题

5.2 不允许继续保留半套正式化、半套临时方案

一旦正式启用 accumulation/composite就必须

  1. 把 draw shader、pass 资源、pass 执行流一起接完整
  2. 把当前直接画到 scene color 的临时路径清掉
  3. 不保留两个语义不同但名字相同的渲染路线

5.3 修复必须由测试驱动收口

本轮所有核心改动都必须由以下验证闭环约束:

  1. gaussian_splat_scene 的三后端输出
  2. 中间调试图可视化检查
  3. 现有 GaussianSplat 资源与缓存相关测试不回退

6. 分阶段计划

Phase 1补齐 3DGS 中间结果观测面

目标:

  1. 在不改渲染语义之前,先把中间状态可视化出来

任务:

  1. 允许 gaussian_splat_scene 在调试模式下输出 accumulation RT
  2. 允许单独检查 sort/order 与 view-data 是否为空或异常
  3. 固化一套最小调试截图流程,避免后续继续靠猜

验收标准:

  1. 可以直接看到 accumulation RT 的内容
  2. 可以区分“prepare 阶段错误”和“draw/composite 阶段错误”

Phase 2把 accumulation surface 正式接入 BuiltinGaussianSplatPass

目标:

  1. BuiltinGaussianSplatPassResources::AccumulationSurface 从未使用状态变成正式执行资源

任务:

  1. 在 pass 执行前按 viewport 尺寸创建或复用 accumulation RT
  2. alpha = 0 清空 accumulation RT
  3. draw 阶段只向 accumulation RT 输出,不再直接写主场景颜色
  4. 明确 accumulation RT 的资源状态流转

验收标准:

  1. draw pass 不再直接绑定主场景颜色附件
  2. accumulation RT 生命周期与 working set 生命周期边界清晰

Phase 3对齐 draw shader 的输出语义与 blend 合约

目标:

  1. 让 splat draw 输出和参考实现使用同一套前向累积语义

任务:

  1. 对齐 draw shader 输出格式
  2. 对齐 draw shader blend 状态
  3. 确认当前相机空间 z 约定下,排序方向与累积方向一致
  4. 不允许通过后端分支打补丁解决语义冲突

验收标准:

  1. draw shader 的颜色输出、alpha 输出、blend 方程是自洽的
  2. PrepareOrder -> Sort -> Draw 是同一套排序约定

Phase 4新增正式的 composite pass

目标:

  1. 把 accumulation RT 稳定地合成回主场景颜色缓冲

任务:

  1. 新增 builtin composite shader
  2. BuiltinGaussianSplatPass 内建立 draw + compose 的完整顺序
  3. 明确主场景颜色、深度与 accumulation RT 的交互边界
  4. 不通过测试侧手写 command list 绕过 renderer

验收标准:

  1. 最终颜色由 composite pass 统一输出
  2. 3DGS pass 对主场景颜色缓冲的写入语义单一清晰

Phase 5回归基线与参数收口

目标:

  1. 在正确渲染路径跑通后,再校正当前测试参数

任务:

  1. 重新评估当前子集数量是否足够形成稳定 GT
  2. 重新评估 _PointScale 的默认值
  3. 必要时重建 GT.ppm
  4. 三后端重新运行并固定基线

验收标准:

  1. gaussian_splat_scene 的 GT 是基于正式渲染路径得到的
  2. 不再把“错误输出截图”继续当成 GT

7. 风险与提前约束

7.1 不能把参考实现照搬成 Unity 特有依赖

本轮只吸收以下内容:

  1. 累积 RT + composite 的渲染语义
  2. 排序与 blend 的契约关系
  3. 中间资源与 draw/composite 的分层方式

不吸收:

  1. Unity 特有 CommandBuffer 接口设计
  2. Unity 运行时生命周期组织方式
  3. Unity 专有材质属性命名与 editor 逻辑

7.2 不能把 accumulation/composite 做成测试专用旁路

这条路径必须属于正式 renderer而不是

  1. 只在 gaussian_splat_scene 里额外手写一套
  2. 只在 D3D12 下工作
  3. 通过测试宏临时切换

7.3 不允许继续保留错误 GT

如果当前 GT.ppm 来自错误渲染路径,就必须重建。
否则后续再怎么修,测试也会被旧基线误导。

8. 完成标志

当以下条件同时成立,这份计划才算完成:

  1. BuiltinGaussianSplatPass 正式使用 accumulation surface
  2. draw shader 与 sort 语义彻底自洽
  3. composite pass 正式接回主场景颜色
  4. gaussian_splat_scene 在 D3D12 / Vulkan / OpenGL 下都能稳定输出正确图像
  5. 调试图证明 accumulation RT 本身干净且可解释
  6. 当前 3DGS 渲染路径中不再残留“直接写 scene color 的临时旧路线”

9. 一句话结论

当前 3DGS 的问题不是“参数没调对”,而是“渲染执行链条还停在错误的临时语义上”。
下一步必须把 Prepare/Sort -> Accumulation Draw -> Composite 这条正式路径一次接完整,再重新建立三后端的 GT 基线。