8.4 KiB
3DGS 渲染路径对齐参考实现修复计划
日期:2026-04-11
1. 文档定位
旧计划《3DGS渲染集成测试与Renderer正式接入计划》已经完成了主体接入工作:
GaussianSplat资源链路已经打通GaussianSplatRendererComponent/VisibleGaussianSplatItem/BuiltinGaussianSplatPass已经落地tests/Rendering/integration/gaussian_splat_scene已经建立
当前剩下的不是“是否接进 Renderer”,而是“当前 Renderer 中的 3DGS 正式路径与参考实现仍有关键偏差,导致画面结果错误”。
因此这份新计划只聚焦当前的渲染正确性修复与测试收口,不再重复旧计划里已经完成的接入事项。
2. 已确认的根因
这轮问题已经不是相机摆放、PLY 导入或简单参数调节问题,而是渲染路径本身与参考实现不一致。
2.1 当前引擎缺少正式的 accumulation + composite 两段式路径
参考实现的关键流程是:
- 先把 splat 绘制到单独的半浮点累积 RT
- splat draw 使用前向累积专用 blend
- 最后再把累积 RT composite 回主场景颜色缓冲
参考位置:
mvs/3DGS-Unity/Shaders/RenderGaussianSplats.shadermvs/3DGS-Unity/Shaders/GaussianComposite.shadermvs/3DGS-Unity/Runtime/GaussianSplatRenderer.cs
当前引擎却是:
- 在
engine/assets/builtin/shaders/gaussian-splat.shader中直接输出到主场景颜色 BuiltinGaussianSplatPass直接把 camera color attachment 作为 render target- 虽然
BuiltinGaussianSplatPassResources已经有AccumulationSurface抽象,但执行路径没有真正使用它
这说明当前实现是“资源抽象已经开始正式化,但执行流仍停在临时路径上”,这是第一根因。
2.2 当前排序方向与当前 blend 方程不匹配
当前引擎:
PrepareOrder阶段使用相机空间viewCenter.z作为排序距离- bitonic 结果本质上是按升序排列
- draw shader 却使用普通透明混合
Blend SrcAlpha OneMinusSrcAlpha
如果保留当前普通透明混合,就应当使用严格的 back-to-front 语义;
如果要对齐参考实现的 front-to-back 累积,就必须同时切到参考的累积 blend 与独立 accumulation target。
也就是说,当前并不是“排序可能有一点不准”,而是“排序约定与 blend 合约本身冲突”。
2.3 当前测试参数只是在放大问题,不是问题本体
当前集成测试里:
- 只取了
65536个 splat 子集 _PointScale = 3.0- 最终输出直接落在主 backbuffer
这些会让错误更明显,但不会单独制造当前这种大面积拖影、糊片、黑色尖刺。
真正的问题仍然是 draw/composite 路径设计错误。
3. 本轮修复目标
本轮只做一件事:把当前引擎中的 3DGS 渲染主链,彻底对齐到参考实现所依赖的那组最小正确语义。
具体目标:
- 建立正式的 accumulation render target
- draw shader 改为服务 accumulation 的输出与 blend 合约
- 新增正式的 composite pass,把 accumulation 结果混回主场景
- 统一排序方向与 blend 语义,不允许继续“排序一套、混合一套”
- 保证
gaussian_splat_scene在 D3D12 / Vulkan / OpenGL 三后端下都能稳定回归
4. 非目标
这轮明确不做:
- 不接 editor 中的 3DGS 显示与交互
- 不做 selection / cutout / 编辑工具链
- 不做 3DGS 的 streaming / LOD / chunk 级高级优化
- 不在这轮重做
GaussianSplatartifact schema - 不引入 compute shader 之外的新渲染架构分支
5. 执行原则
5.1 先对齐正确性,再谈进一步优化
这轮优先级必须是:
- 先把“渲染方程”和“执行路径”对齐
- 先让集成测试输出正确
- 再考虑性能、压缩、子集规模、排序频率等问题
5.2 不允许继续保留半套正式化、半套临时方案
一旦正式启用 accumulation/composite,就必须:
- 把 draw shader、pass 资源、pass 执行流一起接完整
- 把当前直接画到 scene color 的临时路径清掉
- 不保留两个语义不同但名字相同的渲染路线
5.3 修复必须由测试驱动收口
本轮所有核心改动都必须由以下验证闭环约束:
gaussian_splat_scene的三后端输出- 中间调试图可视化检查
- 现有
GaussianSplat资源与缓存相关测试不回退
6. 分阶段计划
Phase 1:补齐 3DGS 中间结果观测面
目标:
- 在不改渲染语义之前,先把中间状态可视化出来
任务:
- 允许
gaussian_splat_scene在调试模式下输出 accumulation RT - 允许单独检查 sort/order 与 view-data 是否为空或异常
- 固化一套最小调试截图流程,避免后续继续靠猜
验收标准:
- 可以直接看到 accumulation RT 的内容
- 可以区分“prepare 阶段错误”和“draw/composite 阶段错误”
Phase 2:把 accumulation surface 正式接入 BuiltinGaussianSplatPass
目标:
- 让
BuiltinGaussianSplatPassResources::AccumulationSurface从未使用状态变成正式执行资源
任务:
- 在 pass 执行前按 viewport 尺寸创建或复用 accumulation RT
- 以
alpha = 0清空 accumulation RT - draw 阶段只向 accumulation RT 输出,不再直接写主场景颜色
- 明确 accumulation RT 的资源状态流转
验收标准:
- draw pass 不再直接绑定主场景颜色附件
- accumulation RT 生命周期与 working set 生命周期边界清晰
Phase 3:对齐 draw shader 的输出语义与 blend 合约
目标:
- 让 splat draw 输出和参考实现使用同一套前向累积语义
任务:
- 对齐 draw shader 输出格式
- 对齐 draw shader blend 状态
- 确认当前相机空间
z约定下,排序方向与累积方向一致 - 不允许通过后端分支打补丁解决语义冲突
验收标准:
- draw shader 的颜色输出、alpha 输出、blend 方程是自洽的
PrepareOrder -> Sort -> Draw是同一套排序约定
Phase 4:新增正式的 composite pass
目标:
- 把 accumulation RT 稳定地合成回主场景颜色缓冲
任务:
- 新增 builtin composite shader
- 在
BuiltinGaussianSplatPass内建立 draw + compose 的完整顺序 - 明确主场景颜色、深度与 accumulation RT 的交互边界
- 不通过测试侧手写 command list 绕过 renderer
验收标准:
- 最终颜色由 composite pass 统一输出
- 3DGS pass 对主场景颜色缓冲的写入语义单一清晰
Phase 5:回归基线与参数收口
目标:
- 在正确渲染路径跑通后,再校正当前测试参数
任务:
- 重新评估当前子集数量是否足够形成稳定 GT
- 重新评估
_PointScale的默认值 - 必要时重建
GT.ppm - 三后端重新运行并固定基线
验收标准:
gaussian_splat_scene的 GT 是基于正式渲染路径得到的- 不再把“错误输出截图”继续当成 GT
7. 风险与提前约束
7.1 不能把参考实现照搬成 Unity 特有依赖
本轮只吸收以下内容:
- 累积 RT + composite 的渲染语义
- 排序与 blend 的契约关系
- 中间资源与 draw/composite 的分层方式
不吸收:
- Unity 特有
CommandBuffer接口设计 - Unity 运行时生命周期组织方式
- Unity 专有材质属性命名与 editor 逻辑
7.2 不能把 accumulation/composite 做成测试专用旁路
这条路径必须属于正式 renderer,而不是:
- 只在
gaussian_splat_scene里额外手写一套 - 只在 D3D12 下工作
- 通过测试宏临时切换
7.3 不允许继续保留错误 GT
如果当前 GT.ppm 来自错误渲染路径,就必须重建。
否则后续再怎么修,测试也会被旧基线误导。
8. 完成标志
当以下条件同时成立,这份计划才算完成:
BuiltinGaussianSplatPass正式使用 accumulation surface- draw shader 与 sort 语义彻底自洽
- composite pass 正式接回主场景颜色
gaussian_splat_scene在 D3D12 / Vulkan / OpenGL 下都能稳定输出正确图像- 调试图证明 accumulation RT 本身干净且可解释
- 当前 3DGS 渲染路径中不再残留“直接写 scene color 的临时旧路线”
9. 一句话结论
当前 3DGS 的问题不是“参数没调对”,而是“渲染执行链条还停在错误的临时语义上”。
下一步必须把 Prepare/Sort -> Accumulation Draw -> Composite 这条正式路径一次接完整,再重新建立三后端的 GT 基线。