Add 3DGS D3D12 MVS bootstrap and PLY loader
This commit is contained in:
245
docs/plan/3DGS-D3D12最小可行系统计划_2026-04-12.md
Normal file
245
docs/plan/3DGS-D3D12最小可行系统计划_2026-04-12.md
Normal file
@@ -0,0 +1,245 @@
|
||||
# 3DGS-D3D12 最小可行系统计划
|
||||
|
||||
日期:2026-04-12
|
||||
|
||||
## 1. 文档定位
|
||||
|
||||
这份计划用于指导 `D:\Xuanchi\Main\XCEngine\mvs\3DGS-D3D12` 的最小可行系统落地。
|
||||
|
||||
当前任务边界已经明确:
|
||||
|
||||
1. 只允许在 `mvs/3DGS-D3D12` 目录内开发与新增文件。
|
||||
2. `engine` 代码只能引用,禁止修改。
|
||||
3. 图形抽象层只能使用现有 `engine` 提供的 `RHI` 接口。
|
||||
4. 本轮目标是先把 3DGS 的最小可行系统跑通,而不是把它正式并入引擎主线。
|
||||
5. 本轮明确不引入 `chunk` 机制。
|
||||
|
||||
因此,这份计划不是“继续修补引擎内已有的 GaussianSplat 路径”,而是“在 MVS 目录内重新搭一条干净的、可验证的、无 chunk 的 3DGS-D3D12 最小链路”。
|
||||
|
||||
## 2. 参考实现与职责拆分
|
||||
|
||||
本轮只参考两条现有实现,各自承担不同职责:
|
||||
|
||||
### 2.1 `mvs/3DGS Unity Renderer`
|
||||
|
||||
用途:
|
||||
|
||||
1. 参考 `.ply` 的读取方式。
|
||||
2. 参考如何从 PLY 属性中提取 3DGS 所需原始数据。
|
||||
3. 参考资源准备阶段的数据布局与字段含义。
|
||||
|
||||
注意:
|
||||
|
||||
1. 这里只借鉴导入与数据准备思路。
|
||||
2. 不照搬 Unity Editor 资产工作流。
|
||||
3. 不引入 chunk。
|
||||
|
||||
### 2.2 `mvs/3DGS-Unity`
|
||||
|
||||
用途:
|
||||
|
||||
1. 参考“干净的无 chunk 渲染路径”。
|
||||
2. 参考 `prepare -> sort -> draw -> composite` 的最小闭环。
|
||||
3. 参考 3DGS 在屏幕空间椭圆展开、混合与合成时的核心着色器语义。
|
||||
|
||||
注意:
|
||||
|
||||
1. 这里重点参考渲染过程,而不是 Unity 的宿主框架。
|
||||
2. 不把 Unity 的 `ScriptableRenderPass`、资产导入器、Inspector 等编辑器逻辑带入本轮实现。
|
||||
|
||||
## 3. 首轮目标
|
||||
|
||||
首轮只完成以下闭环:
|
||||
|
||||
1. 在 `mvs/3DGS-D3D12` 内部加载 `room.ply`。
|
||||
2. 将 PLY 中的高斯数据转换为无 chunk 的运行时缓冲。
|
||||
3. 通过现有 `RHI` 完成 D3D12 路径下的最小渲染。
|
||||
4. 输出一张稳定可观察的结果图,证明房间场景已经被正确绘制。
|
||||
|
||||
首轮验收标准:
|
||||
|
||||
1. 程序能独立编译与运行。
|
||||
2. 不依赖修改 `engine` 才能成立。
|
||||
3. 渲染结果不再是纯黑、纯白或明显错误的撕裂图。
|
||||
4. 渲染链路中不存在任何 chunk 数据结构、chunk 缓冲或 chunk 可见性阶段。
|
||||
|
||||
## 4. 非目标
|
||||
|
||||
本轮明确不做:
|
||||
|
||||
1. 不并入 editor。
|
||||
2. 不接入引擎现有 Renderer 主线。
|
||||
3. 不做 OpenGL / Vulkan 多后端对齐。
|
||||
4. 不做正式资源缓存格式。
|
||||
5. 不做 chunk、cluster、LOD、streaming 等优化层。
|
||||
6. 不做 compute 之外的额外架构扩展。
|
||||
7. 不为迎合当前 MVS 去修改 `engine` 的 `RHI`、Renderer、Resources。
|
||||
|
||||
## 5. 约束与执行原则
|
||||
|
||||
### 5.1 目录约束
|
||||
|
||||
本轮新增内容应尽量收敛在 `mvs/3DGS-D3D12` 内,例如:
|
||||
|
||||
1. `src/`:程序入口、渲染器、相机、数据上传。
|
||||
2. `include/`:本地头文件。
|
||||
3. `shaders/`:本地 HLSL 或中间 shader 资源。
|
||||
4. `assets/`:本地测试资源或生成物描述。
|
||||
5. `third_party/`:仅当 MVS 自己确实需要额外小型依赖时使用。
|
||||
|
||||
### 5.2 RHI 使用原则
|
||||
|
||||
1. 只调用现有 `engine` 的 `RHI` 公共接口。
|
||||
2. 如果发现最小系统缺失某项能力,优先在 MVS 内通过更简单的组织方式规避。
|
||||
3. 若确实被 `RHI` 能力边界阻塞,先记录问题并汇报,不允许直接改 `engine`。
|
||||
|
||||
### 5.3 数据路径原则
|
||||
|
||||
1. 整个系统只保留 positions、other、color、SH 等无 chunk 基础数据。
|
||||
2. 不生成 chunk header。
|
||||
3. 不上传 chunk buffer。
|
||||
4. 不做 visible chunk 标记。
|
||||
5. 不保留任何为了兼容旧 chunk 方案而加的临时分支。
|
||||
|
||||
## 6. 技术路线
|
||||
|
||||
### Phase 1:梳理 3DGS-D3D12 的骨架与构建入口
|
||||
|
||||
目标:
|
||||
|
||||
1. 确认 `mvs/3DGS-D3D12` 当前是否只有 `room.ply`。
|
||||
2. 建立最小的可执行工程骨架。
|
||||
3. 打通对 `engine` 中 `RHI` 的引用与链接。
|
||||
|
||||
任务:
|
||||
|
||||
1. 规划 `CMakeLists.txt` 与目录结构。
|
||||
2. 建立窗口、设备、交换链、命令提交、离屏或在屏渲染的最小入口。
|
||||
3. 跑通一个“清屏可显示”的基础版本。
|
||||
|
||||
验收:
|
||||
|
||||
1. `3DGS-D3D12` 可独立编译。
|
||||
2. 程序能启动并输出基础画面。
|
||||
|
||||
### Phase 2:实现无 chunk 的 PLY 读取与运行时数据打包
|
||||
|
||||
目标:
|
||||
|
||||
1. 参考 `mvs/3DGS Unity Renderer`,在 MVS 内部完成 PLY 读取。
|
||||
2. 输出适合渲染阶段直接上传的高斯原始数组。
|
||||
|
||||
任务:
|
||||
|
||||
1. 解析 PLY header 与顶点属性。
|
||||
2. 提取 position、rotation、scale、opacity、color/SH 等字段。
|
||||
3. 明确字段的排列顺序、类型与归一化方式。
|
||||
4. 生成 MVS 本地 `GaussianSplatSceneData`。
|
||||
|
||||
验收:
|
||||
|
||||
1. `room.ply` 可被成功读取。
|
||||
2. 点数量、字段长度、边界盒等基础统计合理。
|
||||
3. 整条导入链中完全没有 chunk 概念。
|
||||
|
||||
### Phase 3:对齐无 chunk 的 GPU 数据布局与上传
|
||||
|
||||
目标:
|
||||
|
||||
1. 把导入结果上传到 GPU。
|
||||
2. 数据布局尽量贴近 `mvs/3DGS-Unity` 的渲染输入。
|
||||
|
||||
任务:
|
||||
|
||||
1. 设计 positions / other / color / SH 的 GPU buffer。
|
||||
2. 建立与着色器绑定一致的 SRV/UAV 视图。
|
||||
3. 为排序与绘制准备 index、distance、view-data 等工作缓冲。
|
||||
|
||||
验收:
|
||||
|
||||
1. GPU 侧所有关键缓冲都能正确创建。
|
||||
2. 每个绑定槽位与 shader 语义一一对应。
|
||||
3. 不包含 chunk buffer / visible chunk buffer。
|
||||
|
||||
### Phase 4:先打通 prepare 与 sort
|
||||
|
||||
目标:
|
||||
|
||||
1. 先验证“高斯数据被相机看到并被正确排序”。
|
||||
2. 在 draw 之前把中间结果可视化或可检查化。
|
||||
|
||||
任务:
|
||||
|
||||
1. 参考 `mvs/3DGS-Unity` 的 prepare 语义,计算每个 splat 的 view-space 信息。
|
||||
2. 生成排序距离。
|
||||
3. 跑通最小排序路径。
|
||||
4. 必要时增加调试输出,用于检查 order / distance / 计数是否异常。
|
||||
|
||||
验收:
|
||||
|
||||
1. prepare 结果不是全零或明显错误。
|
||||
2. sort 输出索引顺序稳定。
|
||||
|
||||
### Phase 5:对齐 draw 与 composite
|
||||
|
||||
目标:
|
||||
|
||||
1. 参考 `mvs/3DGS-Unity` 的“干净无 chunk 渲染路径”把核心画面先画出来。
|
||||
|
||||
任务:
|
||||
|
||||
1. 对齐 Gaussian splat draw shader 的主要输入输出语义。
|
||||
2. 对齐椭圆展开、覆盖范围与透明混合约定。
|
||||
3. 建立 accumulation target。
|
||||
4. 建立 composite pass,把 accumulation 结果合回最终颜色。
|
||||
|
||||
验收:
|
||||
|
||||
1. 输出图中能看出 `room.ply` 对应的房间结构。
|
||||
2. 不出现整屏纯黑、纯白、随机撕裂。
|
||||
|
||||
### Phase 6:收口与验证
|
||||
|
||||
目标:
|
||||
|
||||
1. 固化最小系统结果,形成稳定基线。
|
||||
|
||||
任务:
|
||||
|
||||
1. 规范运行命令与资源路径。
|
||||
2. 输出一张固定命名的结果图作为检查基线。
|
||||
3. 清理调试残留与临时分支。
|
||||
4. 补一份 MVS 内局部说明文档。
|
||||
|
||||
验收:
|
||||
|
||||
1. 代码、资源、着色器都收敛在 `mvs/3DGS-D3D12`。
|
||||
2. 运行方式清晰。
|
||||
3. 基线截图稳定。
|
||||
|
||||
## 7. 关键风险
|
||||
|
||||
### 7.1 PLY 属性语义与当前样例不一致
|
||||
|
||||
如果 `room.ply` 的字段命名、顺序或编码方式与参考加载器假设不一致,最先要修的是导入器映射,不是渲染器。
|
||||
|
||||
### 7.2 RHI 能力与参考实现存在接口差
|
||||
|
||||
如果 Unity 参考依赖的某些资源绑定或 compute 流程不能直接一比一照搬,本轮优先在 `mvs/3DGS-D3D12` 内部重排执行方式,而不是去动 `engine`。
|
||||
|
||||
### 7.3 排序与混合契约不一致
|
||||
|
||||
3DGS 最容易出错的不是“有没有画出来”,而是排序方向、alpha 累积与 composite 契约是否一致。本轮必须把这三者当成同一个问题处理,禁止分开打补丁。
|
||||
|
||||
## 8. 本轮完成后的下一步
|
||||
|
||||
当 `mvs/3DGS-D3D12` 的无 chunk 最小系统跑通后,下一步才有意义讨论:
|
||||
|
||||
1. 是否把这条路径收编进引擎正式 Renderer。
|
||||
2. 是否把 PLY 导入升级成正式资源导入器。
|
||||
3. 是否在引擎层补 structured buffer / compute / renderer pass 抽象。
|
||||
4. 是否接入 editor 与资产缓存。
|
||||
|
||||
在这之前,所有工作都应服务于一个目标:
|
||||
|
||||
先在 `mvs/3DGS-D3D12` 内证明“无 chunk 的 3DGS-D3D12 + 现有 RHI”这条路是通的。
|
||||
@@ -1,248 +0,0 @@
|
||||
# 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 基线。
|
||||
Reference in New Issue
Block a user