694 lines
18 KiB
Markdown
694 lines
18 KiB
Markdown
|
|
# 3DGS 专用 PLY 导入器与 GaussianSplat 资源缓存正式化计划
|
|||
|
|
|
|||
|
|
日期:2026-04-10
|
|||
|
|
|
|||
|
|
## 1. 文档定位
|
|||
|
|
|
|||
|
|
这份计划只覆盖 3DGS 落地中的前两层基础设施:
|
|||
|
|
|
|||
|
|
1. `3DGS 专用 PLY importer`
|
|||
|
|
2. `GaussianSplat 资源 / Artifact / ResourceManager / 缓存层`
|
|||
|
|
|
|||
|
|
这份计划明确不讨论以下内容:
|
|||
|
|
|
|||
|
|
1. 不实现最终的 3DGS 渲染 pass
|
|||
|
|
2. 不实现 editor 里的 3DGS 编辑工具
|
|||
|
|
3. 不实现 cutout、selection、导出、相机激活等 Unity 参考项目中的高级功能
|
|||
|
|
4. 不提前把 3DGS 强行塞进现有 mesh / volume 路径
|
|||
|
|
|
|||
|
|
这份计划的目标不是“先把 `.ply` 读出来”,而是把 3DGS 资产链正式纳入引擎现有的资源系统,使它从一开始就是一条可缓存、可复用、可异步、可测试、可长期维护的正式路径。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 当前参考与现状
|
|||
|
|
|
|||
|
|
当前参考工程是:
|
|||
|
|
|
|||
|
|
1. [mvs/3DGS-Unity](D:/Xuanchi/Main/XCEngine/mvs/3DGS-Unity)
|
|||
|
|
|
|||
|
|
当前测试样本是:
|
|||
|
|
|
|||
|
|
1. [room.ply](D:/Xuanchi/Main/XCEngine/mvs/3DGS-Unity/room.ply)
|
|||
|
|
|
|||
|
|
当前已确认的事实:
|
|||
|
|
|
|||
|
|
1. `3DGS-Unity` 并不是运行时直接渲染 `.ply`,而是先把 `.ply` 转成更接近 GPU 消费形态的运行时资产。
|
|||
|
|
2. 它的导入工作流核心在 [GaussianSplatAssetCreator.cs](D:/Xuanchi/Main/XCEngine/mvs/3DGS-Unity/Editor/GaussianSplatAssetCreator.cs)。
|
|||
|
|
3. 它的 `.ply` 读取器 [PLYFileReader.cs](D:/Xuanchi/Main/XCEngine/mvs/3DGS-Unity/Editor/Utils/PLYFileReader.cs) 本质上是一个偏工程化的快速路径,不是健壮的通用 PLY 解析器。
|
|||
|
|
4. 它的运行时资产 [GaussianSplatAsset.cs](D:/Xuanchi/Main/XCEngine/mvs/3DGS-Unity/Runtime/GaussianSplatAsset.cs) 已经把数据拆成了 `pos / other / sh / color / chunk` 几类 GPU 资源。
|
|||
|
|
5. 它的运行时渲染 [GaussianSplatRenderer.cs](D:/Xuanchi/Main/XCEngine/mvs/3DGS-Unity/Runtime/GaussianSplatRenderer.cs) 依赖 compute、StructuredBuffer、RawBuffer、procedural draw、fullscreen composite。
|
|||
|
|
|
|||
|
|
对当前引擎的现状判断:
|
|||
|
|
|
|||
|
|
1. 引擎已经具备 `StructuredBuffer / RawBuffer / RWStructuredBuffer / RWRawBuffer` 级别的 shader 资源识别能力。
|
|||
|
|
2. 引擎已经具备 compute shader 与 `Dispatch` 的 RHI 基础能力。
|
|||
|
|
3. 引擎已经具备 runtime material buffer binding 能力。
|
|||
|
|
4. 引擎已经具备 `AssetDatabase -> Library/Artifacts -> ResourceManager` 的正式资源链。
|
|||
|
|
5. 引擎当前还没有 `GaussianSplat` 这种正式资源类型。
|
|||
|
|
6. 引擎当前还没有 3DGS 专用 importer、artifact schema、loader、GPU residency cache。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 本轮最核心的架构决策
|
|||
|
|
|
|||
|
|
### 3.1 不允许运行时直接消费 `.ply`
|
|||
|
|
|
|||
|
|
正式方案必须是:
|
|||
|
|
|
|||
|
|
1. `Assets/*.ply`
|
|||
|
|
2. 经过 `GaussianSplatImporter`
|
|||
|
|
3. 生成 `Library/Artifacts/.../main.xcgsplat`
|
|||
|
|
4. 运行时只加载 `xcgsplat`
|
|||
|
|
|
|||
|
|
不允许的错误方案:
|
|||
|
|
|
|||
|
|
1. renderer 首次遇到 `.ply` 时再现场解析
|
|||
|
|
2. component 里直接持有 `.ply` 文件句柄
|
|||
|
|
3. 把 `.ply` 读取逻辑塞进 render pass
|
|||
|
|
4. 为了尽快出图先做“临时直接加载 `.ply`”然后以后再回收
|
|||
|
|
|
|||
|
|
原因很明确:
|
|||
|
|
|
|||
|
|
1. `.ply` 是 source asset,不是 runtime-ready asset
|
|||
|
|
2. 直接 runtime 解析会破坏 `AssetDatabase / ResourceManager / Library` 体系
|
|||
|
|
3. 3DGS 数据量远大于普通 mesh,更不能把 source 解析和 GPU 上传压到 draw path 上
|
|||
|
|
|
|||
|
|
### 3.2 不做通用 PLY 导入器,先做 3DGS 专用 PLY 导入器
|
|||
|
|
|
|||
|
|
本轮 importer 的职责不是支持一切 PLY 变体,而是支持当前 3DGS 工作流所需的那类 PLY。
|
|||
|
|
|
|||
|
|
正式边界是:
|
|||
|
|
|
|||
|
|
1. 支持 `binary_little_endian`
|
|||
|
|
2. 只关心 `element vertex`
|
|||
|
|
3. 通过属性名映射识别 3DGS 语义字段
|
|||
|
|
4. 对不支持的属性布局给出明确错误
|
|||
|
|
|
|||
|
|
不做的事:
|
|||
|
|
|
|||
|
|
1. 不支持带面片索引的通用模型 PLY
|
|||
|
|
2. 不支持 ASCII PLY
|
|||
|
|
3. 不支持任意 list property
|
|||
|
|
4. 不支持“能读但语义不清晰”的模糊推断
|
|||
|
|
|
|||
|
|
这不是退让,而是边界明确。当前目标是 3DGS 正式化,不是通用点云 SDK。
|
|||
|
|
|
|||
|
|
### 3.3 运行时正式资源类型命名为 `GaussianSplat`
|
|||
|
|
|
|||
|
|
建议引入:
|
|||
|
|
|
|||
|
|
1. `ResourceType::GaussianSplat`
|
|||
|
|
2. `Resources::GaussianSplat`
|
|||
|
|
3. `GaussianSplatLoader`
|
|||
|
|
4. `GaussianSplatImporter`
|
|||
|
|
|
|||
|
|
不建议把运行时资源叫:
|
|||
|
|
|
|||
|
|
1. `GaussianSplatAsset`
|
|||
|
|
2. `GaussianAsset`
|
|||
|
|
3. `PLYAsset`
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
|
|||
|
|
1. 引擎当前 `ResourceType` 命名体系都是运行时资源名,不是 editor 资产名
|
|||
|
|
2. `Asset` 更适合出现在导入流程和文档语义中,不适合塞进正式 runtime `ResourceType`
|
|||
|
|
|
|||
|
|
### 3.4 Artifact 采用单文件主 artifact,而不是 Unity 式多 TextAsset 拼装
|
|||
|
|
|
|||
|
|
建议正式主 artifact 为:
|
|||
|
|
|
|||
|
|
1. `main.xcgsplat`
|
|||
|
|
|
|||
|
|
不建议照抄 Unity MVS 的多文件拆分为:
|
|||
|
|
|
|||
|
|
1. `*_pos.bytes`
|
|||
|
|
2. `*_other.bytes`
|
|||
|
|
3. `*_sh.bytes`
|
|||
|
|
4. `*_col.bytes`
|
|||
|
|
5. `*_chk.bytes`
|
|||
|
|
|
|||
|
|
Unity 那样做是受 Unity 资产模型约束。我们自己的引擎不需要跟着它的工程妥协走。
|
|||
|
|
|
|||
|
|
本轮更合理的正式方案是:
|
|||
|
|
|
|||
|
|
1. 单个 `xcgsplat` 文件包含 header、section table、payload
|
|||
|
|
2. loader 一次读入 metadata,按 section 定位各 payload
|
|||
|
|
3. 后续如果要做分段流式或 memory mapping,再在 schema 上扩展,不先把文件形态做碎
|
|||
|
|
|
|||
|
|
这样做的好处:
|
|||
|
|
|
|||
|
|
1. artifact 边界清晰
|
|||
|
|
2. `ArtifactDB` 记录简单
|
|||
|
|
3. 依赖跟踪简单
|
|||
|
|
4. reimport 稳定
|
|||
|
|
5. 不会出现多 sidecar 丢失或部分过期的问题
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 对参考 MVS 的正式吸收方式
|
|||
|
|
|
|||
|
|
`mvs/3DGS-Unity` 里真正值得吸收的是流程,不是实现细节原样照搬。
|
|||
|
|
|
|||
|
|
本轮吸收的内容:
|
|||
|
|
|
|||
|
|
1. 输入语义
|
|||
|
|
2. 数据重排思路
|
|||
|
|
3. 运行时数据拆分维度
|
|||
|
|
4. `chunk` 概念
|
|||
|
|
5. 颜色纹理化而不是纯 buffer 化
|
|||
|
|
6. 未来 compute 排序与 view-data 预处理对资源格式的需求
|
|||
|
|
|
|||
|
|
本轮不直接照搬的内容:
|
|||
|
|
|
|||
|
|
1. Unity 的 `TextAsset` 资产组织方式
|
|||
|
|
2. 依赖 `UnsafeUtility.SizeOf<InputSplatData>() == vertexStride` 的固定内存布局导入
|
|||
|
|
3. editor 窗口与工具链
|
|||
|
|
4. HDRP/URP feature 接入方式
|
|||
|
|
5. 所有编辑态 GPU buffer
|
|||
|
|
|
|||
|
|
简单说:
|
|||
|
|
|
|||
|
|
1. 流程借鉴
|
|||
|
|
2. 数据语义借鉴
|
|||
|
|
3. 工程架构不照抄 Unity 的壳
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. `room.ply` 的正式支持目标
|
|||
|
|
|
|||
|
|
当前基线样本 [room.ply](D:/Xuanchi/Main/XCEngine/mvs/3DGS-Unity/room.ply) 已确认包含如下字段:
|
|||
|
|
|
|||
|
|
1. `x y z`
|
|||
|
|
2. `nx ny nz`
|
|||
|
|
3. `f_dc_0..2`
|
|||
|
|
4. `f_rest_0..44`
|
|||
|
|
5. `opacity`
|
|||
|
|
6. `scale_0..2`
|
|||
|
|
7. `rot_0..3`
|
|||
|
|
|
|||
|
|
本轮 importer 至少必须把这类文件稳定导入。
|
|||
|
|
|
|||
|
|
本轮导入结果必须包含:
|
|||
|
|
|
|||
|
|
1. splat 数量
|
|||
|
|
2. bounds
|
|||
|
|
3. position
|
|||
|
|
4. rotation
|
|||
|
|
5. scale
|
|||
|
|
6. opacity
|
|||
|
|
7. color / dc0
|
|||
|
|
8. SH 数据
|
|||
|
|
9. 供后续 chunk 化、排序、view-data 预计算所需的稳定 layout
|
|||
|
|
|
|||
|
|
本轮不要求:
|
|||
|
|
|
|||
|
|
1. 用 room.ply 直接出图
|
|||
|
|
2. 完成 chunk 压缩优化后的最终视觉验证
|
|||
|
|
|
|||
|
|
但必须做到:
|
|||
|
|
|
|||
|
|
1. room.ply 可以稳定导入成正式 artifact
|
|||
|
|
2. runtime 可以正式加载该 artifact
|
|||
|
|
3. 资源缓存与异步链路已经为后续渲染阶段准备好
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 目标资源模型设计
|
|||
|
|
|
|||
|
|
### 6.1 `Resources::GaussianSplat`
|
|||
|
|
|
|||
|
|
建议 `GaussianSplat` 运行时资源至少包含:
|
|||
|
|
|
|||
|
|
1. `splatCount`
|
|||
|
|
2. `boundsMin / boundsMax`
|
|||
|
|
3. `dataFormatVersion`
|
|||
|
|
4. `positionFormat`
|
|||
|
|
5. `otherFormat`
|
|||
|
|
6. `colorFormat`
|
|||
|
|
7. `shFormat`
|
|||
|
|
8. `chunkCount`
|
|||
|
|
9. `cameraInfoCount`
|
|||
|
|
10. 各 section 的只读数据视图
|
|||
|
|
|
|||
|
|
这里的 section 建议为:
|
|||
|
|
|
|||
|
|
1. `positions`
|
|||
|
|
2. `other`
|
|||
|
|
3. `color`
|
|||
|
|
4. `sh`
|
|||
|
|
5. `chunks`
|
|||
|
|
6. `cameras`
|
|||
|
|
|
|||
|
|
### 6.2 `other` 的语义边界
|
|||
|
|
|
|||
|
|
建议 `other` 区域承担:
|
|||
|
|
|
|||
|
|
1. rotation
|
|||
|
|
2. scale
|
|||
|
|
3. opacity
|
|||
|
|
4. 可选 SH 索引或 chunk 相关辅助字段
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
|
|||
|
|
1. 这与参考 MVS 的消费模型更接近
|
|||
|
|
2. compute 阶段天然会把位置和其它数据拆开消费
|
|||
|
|
3. 将来做压缩时,位置和其它数据的量化策略也不同
|
|||
|
|
|
|||
|
|
### 6.3 `color` 保持纹理友好布局
|
|||
|
|
|
|||
|
|
建议 `color` section 不是简单“每 splat 一行 float4”,而是直接按运行时纹理消费友好的布局存储。
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
|
|||
|
|
1. 参考 MVS 最终就是把颜色上传成纹理
|
|||
|
|
2. 对 3DGS 而言,颜色作为纹理读取是合理路径
|
|||
|
|
3. 如果导入期就固化好 texel 布局,运行时不必再做一次昂贵重排
|
|||
|
|
|
|||
|
|
### 6.4 `chunks` 作为正式字段预留
|
|||
|
|
|
|||
|
|
即使第一阶段先允许 `chunkCount == 0`,artifact schema 也要正式留出 chunk 区域。
|
|||
|
|
|
|||
|
|
因为:
|
|||
|
|
|
|||
|
|
1. chunk 数据不是可有可无的小优化,它影响后续压缩、解码和排序输入
|
|||
|
|
2. 后面一旦渲染 pass 接上,就会很自然依赖 chunk
|
|||
|
|
3. 现在先把 schema 打对,比后面再迁移 artifact 版本更划算
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. Importer 设计
|
|||
|
|
|
|||
|
|
### 7.1 引入 `GaussianSplatImporter`
|
|||
|
|
|
|||
|
|
`AssetDatabase` 对 `.ply` 的识别不应直接复用 `ModelImporter`。
|
|||
|
|
|
|||
|
|
建议规则:
|
|||
|
|
|
|||
|
|
1. `.ply` 不作为通用模型格式挂进 `ModelImporter`
|
|||
|
|
2. 本轮把 `.ply` 明确识别为 `GaussianSplatImporter`
|
|||
|
|
3. 后续如果将来要支持“通用点云 PLY”,再单独扩展,不污染当前 3DGS 主线
|
|||
|
|
|
|||
|
|
### 7.2 Header 解析不能依赖固定顺序
|
|||
|
|
|
|||
|
|
正式解析流程必须是:
|
|||
|
|
|
|||
|
|
1. 读取 header
|
|||
|
|
2. 收集 `element vertex`
|
|||
|
|
3. 收集每个 `property` 的名字、类型、偏移
|
|||
|
|
4. 建立 3DGS 语义字段到 property 的映射
|
|||
|
|
5. 校验必需字段是否完整
|
|||
|
|
|
|||
|
|
不允许的方案:
|
|||
|
|
|
|||
|
|
1. 直接假定 `InputSplatData` 与文件二进制布局完全一致
|
|||
|
|
2. 直接假定 `f_rest_*` 顺序永远固定且不校验
|
|||
|
|
3. 因为 room.ply 能过就默认所有训练器导出的 PLY 都一样
|
|||
|
|
|
|||
|
|
### 7.3 importer 输出的是 cooked runtime layout,不是 source mirror
|
|||
|
|
|
|||
|
|
导入器的正式职责不是把 `.ply` 原样搬进 artifact,而是做以下转换:
|
|||
|
|
|
|||
|
|
1. 按语义解包 source data
|
|||
|
|
2. 生成规范化内部 splat 记录
|
|||
|
|
3. 计算 bounds
|
|||
|
|
4. 可选做 Morton reorder
|
|||
|
|
5. 可选做 chunk 构建
|
|||
|
|
6. 输出运行时友好的 section layout
|
|||
|
|
|
|||
|
|
这一步就是 source -> cooked artifact,而不是 source -> source copy。
|
|||
|
|
|
|||
|
|
### 7.4 关于压缩策略
|
|||
|
|
|
|||
|
|
本轮计划分两步:
|
|||
|
|
|
|||
|
|
1. 第一阶段先实现无损或近无损基础 cooked 布局
|
|||
|
|
2. 第二阶段再把参考 MVS 的压缩格式体系正式移植进来
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
|
|||
|
|
1. 先把 artifact、loader、cache 链路跑通
|
|||
|
|
2. 再叠加压缩和 chunking
|
|||
|
|
3. 避免 importer、artifact schema、runtime loader、未来 renderer 四件事同时出错
|
|||
|
|
|
|||
|
|
第一阶段允许:
|
|||
|
|
|
|||
|
|
1. `position = float32`
|
|||
|
|
2. `other = float32 / uint32 packed`
|
|||
|
|
3. `color = RGBA32F` 或 `RGBA16F`
|
|||
|
|
4. `sh = float32`
|
|||
|
|
5. `chunk = 0`
|
|||
|
|
|
|||
|
|
第二阶段再引入:
|
|||
|
|
|
|||
|
|
1. `Norm16 / Norm11 / Norm6`
|
|||
|
|
2. `BC7 / Norm8x4`
|
|||
|
|
3. `SH clustering`
|
|||
|
|
4. `chunk` 正式压缩路径
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. Artifact 设计
|
|||
|
|
|
|||
|
|
### 8.1 主文件
|
|||
|
|
|
|||
|
|
主文件建议:
|
|||
|
|
|
|||
|
|
1. `main.xcgsplat`
|
|||
|
|
|
|||
|
|
### 8.2 文件内容建议
|
|||
|
|
|
|||
|
|
建议 `xcgsplat` 文件包含:
|
|||
|
|
|
|||
|
|
1. 文件头
|
|||
|
|
2. schema version
|
|||
|
|
3. source metadata snapshot
|
|||
|
|
4. splat metadata
|
|||
|
|
5. section table
|
|||
|
|
6. payload blob
|
|||
|
|
|
|||
|
|
section table 至少描述:
|
|||
|
|
|
|||
|
|
1. section type
|
|||
|
|
2. byte offset
|
|||
|
|
3. byte size
|
|||
|
|
4. element count
|
|||
|
|
5. element stride
|
|||
|
|
6. format enum
|
|||
|
|
|
|||
|
|
### 8.3 version 策略
|
|||
|
|
|
|||
|
|
建议单独引入:
|
|||
|
|
|
|||
|
|
1. `kGaussianSplatArtifactSchemaVersion`
|
|||
|
|
|
|||
|
|
不要复用其它 importer 的 schema version。
|
|||
|
|
|
|||
|
|
版本提升触发条件:
|
|||
|
|
|
|||
|
|
1. section 布局改变
|
|||
|
|
2. chunk 编码改变
|
|||
|
|
3. 颜色纹理布局改变
|
|||
|
|
4. SH 格式或 camera 区块布局改变
|
|||
|
|
|
|||
|
|
### 8.4 `.meta` 设计
|
|||
|
|
|
|||
|
|
即使本轮先不做完整 Inspector,也应该为后续 importer settings 预留正式字段。
|
|||
|
|
|
|||
|
|
建议至少预留:
|
|||
|
|
|
|||
|
|
1. `reorderMorton`
|
|||
|
|
2. `buildChunks`
|
|||
|
|
3. `positionFormat`
|
|||
|
|
4. `otherFormat`
|
|||
|
|
5. `colorFormat`
|
|||
|
|
6. `shFormat`
|
|||
|
|
7. `importCameras`
|
|||
|
|
|
|||
|
|
第一阶段如果先不开放 UI,也要把默认设置结构体和 hash 纳入 artifact key 计算。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. Loader 与 ResourceManager 接入
|
|||
|
|
|
|||
|
|
### 9.1 `GaussianSplatLoader`
|
|||
|
|
|
|||
|
|
需要新增:
|
|||
|
|
|
|||
|
|
1. `GaussianSplatLoader`
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
|
|||
|
|
1. 读取 `xcgsplat`
|
|||
|
|
2. 构建 `Resources::GaussianSplat`
|
|||
|
|
3. 提供各 section 的稳定只读视图
|
|||
|
|
|
|||
|
|
### 9.2 `ResourceManager` 正式接入
|
|||
|
|
|
|||
|
|
正式链路应支持:
|
|||
|
|
|
|||
|
|
1. `Load<GaussianSplat>("Assets/.../room.ply")`
|
|||
|
|
2. `AssetDatabase::EnsureArtifact(...)`
|
|||
|
|
3. `ResourceManager` 实际加载 `main.xcgsplat`
|
|||
|
|
|
|||
|
|
也必须支持:
|
|||
|
|
|
|||
|
|
1. `Load<GaussianSplat>("Library/Artifacts/.../main.xcgsplat")`
|
|||
|
|
|
|||
|
|
### 9.3 不能把 GPU 上传塞进 loader
|
|||
|
|
|
|||
|
|
`GaussianSplatLoader` 只负责 CPU 运行时资源,不负责 GPU residency。
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
|
|||
|
|
1. loader 属于资源层
|
|||
|
|
2. GPU residency 属于渲染缓存层
|
|||
|
|
3. 如果在 loader 里直接创 GPU 资源,会重复 volume 这条链已经暴露过的架构问题
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10. 缓存与预热设计
|
|||
|
|
|
|||
|
|
### 10.1 资源缓存层必须提前设计 GPU residency 状态机
|
|||
|
|
|
|||
|
|
即使本轮还不接最终 render pass,也必须把状态机设计写进正式方案:
|
|||
|
|
|
|||
|
|
1. `Uninitialized`
|
|||
|
|
2. `CpuReady`
|
|||
|
|
3. `GpuUploading`
|
|||
|
|
4. `GpuReady`
|
|||
|
|
5. `Failed`
|
|||
|
|
|
|||
|
|
后续 `BuiltinGaussianSplatPass` 只能消费:
|
|||
|
|
|
|||
|
|
1. `GpuReady`
|
|||
|
|
|
|||
|
|
不允许 draw path 现场把 `CpuReady -> GpuReady` 做完。
|
|||
|
|
|
|||
|
|
### 10.2 建议新增 `CachedGaussianSplat`
|
|||
|
|
|
|||
|
|
建议未来挂在 `RenderResourceCache` 或其正式拆分后的 GPU 资源缓存模块中。
|
|||
|
|
|
|||
|
|
它至少应持有:
|
|||
|
|
|
|||
|
|
1. `posBuffer`
|
|||
|
|
2. `otherBuffer`
|
|||
|
|
3. `shBuffer`
|
|||
|
|
4. `colorTexture`
|
|||
|
|
5. `chunkBuffer`
|
|||
|
|
6. `sortKeyBuffer`
|
|||
|
|
7. `sortDistanceBuffer`
|
|||
|
|
8. `viewDataBuffer`
|
|||
|
|
9. runtime-ready flag / state
|
|||
|
|
|
|||
|
|
本轮即使还不把所有 GPU 辅助 buffer 全建出来,也要把正式边界写清楚:
|
|||
|
|
|
|||
|
|
1. asset static payload buffer/texture
|
|||
|
|
2. per-frame transient / reusable working buffer
|
|||
|
|
|
|||
|
|
### 10.3 首次可见前预热,而不是首次 draw 同步补做
|
|||
|
|
|
|||
|
|
这点必须作为硬约束写死:
|
|||
|
|
|
|||
|
|
1. `GaussianSplat` 被场景反序列化后,CPU artifact 加载完成就进入 GPU 预热队列
|
|||
|
|
2. GPU 上传在后台或明确的准备阶段完成
|
|||
|
|
3. 首次 draw 只允许跳过未 ready 对象,不允许同步创建大资源
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
|
|||
|
|
1. 3DGS 资产通常很大
|
|||
|
|
2. room.ply 这种样本数据量已经足够把 draw path 压垮
|
|||
|
|
3. 当前 volume 这条链已经证明“首次绘制再上传”不是可接受正式方案
|
|||
|
|
|
|||
|
|
### 10.4 warm cache 验收标准
|
|||
|
|
|
|||
|
|
本轮资源 / 缓存层至少要达到:
|
|||
|
|
|
|||
|
|
1. 第二次加载 room.ply 时不重新解析 source `.ply`
|
|||
|
|
2. 直接命中 `Library/Artifacts`
|
|||
|
|
3. `ResourceManager` 不会因为 cache hit 又走 source importer
|
|||
|
|
4. 后续 GPU 预热可以稳定复用 artifact 输出
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 11. 测试计划
|
|||
|
|
|
|||
|
|
### 11.1 基线样本
|
|||
|
|
|
|||
|
|
统一使用:
|
|||
|
|
|
|||
|
|
1. [room.ply](D:/Xuanchi/Main/XCEngine/mvs/3DGS-Unity/room.ply)
|
|||
|
|
|
|||
|
|
它将承担:
|
|||
|
|
|
|||
|
|
1. importer 基线
|
|||
|
|
2. artifact 基线
|
|||
|
|
3. cache hit 基线
|
|||
|
|
4. future renderer 接入基线
|
|||
|
|
|
|||
|
|
### 11.2 Unit Tests
|
|||
|
|
|
|||
|
|
本轮至少要补齐以下单测:
|
|||
|
|
|
|||
|
|
1. `PLY header parser` 正确识别 `vertexCount / properties / offsets`
|
|||
|
|
2. `GaussianSplatImporter` 能正确识别 room.ply 的必需字段
|
|||
|
|
3. 缺字段时给出明确错误
|
|||
|
|
4. 非法格式时给出明确错误
|
|||
|
|
5. `xcgsplat` 写入 / 读取 roundtrip 正确
|
|||
|
|
6. `GaussianSplatLoader` 能读取 artifact 并恢复 metadata 与 section view
|
|||
|
|
7. `ResourceManager` 能从 `Assets/.../room.ply` 正式加载 `GaussianSplat`
|
|||
|
|
8. `AssetDatabase` 对 `.ply` 的 `EnsureArtifact` 能稳定复用
|
|||
|
|
|
|||
|
|
### 11.3 Integration Tests
|
|||
|
|
|
|||
|
|
本轮先做资源链集成测试,不做最终出图测试。
|
|||
|
|
|
|||
|
|
至少要有:
|
|||
|
|
|
|||
|
|
1. `room.ply -> EnsureArtifact -> Load<GaussianSplat>` 全链通过
|
|||
|
|
2. 二次加载命中 artifact,不触发 reimport
|
|||
|
|
3. 修改 source writeTime 后能触发 reimport
|
|||
|
|
4. 清库后能重建 artifact
|
|||
|
|
|
|||
|
|
### 11.4 为后续渲染阶段准备的 smoke test
|
|||
|
|
|
|||
|
|
虽然本轮不做 3DGS pass,但建议提前补一个 GPU 资源 smoke test:
|
|||
|
|
|
|||
|
|
1. 读取 `GaussianSplat`
|
|||
|
|
2. 构建最小 GPU cache entry
|
|||
|
|
3. 创建 `pos/other/sh/chunk` buffer 与 `color` texture
|
|||
|
|
4. 验证状态进入 `GpuReady`
|
|||
|
|
|
|||
|
|
这样后续 renderer 接入时,不会把“资源问题”和“渲染问题”混成一团。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 12. 分阶段执行计划
|
|||
|
|
|
|||
|
|
### Phase 1:资源类型与 artifact schema 落地
|
|||
|
|
|
|||
|
|
目标:
|
|||
|
|
|
|||
|
|
1. 正式引入 `ResourceType::GaussianSplat`
|
|||
|
|
2. 正式引入 `Resources::GaussianSplat`
|
|||
|
|
3. 正式定义 `xcgsplat` artifact schema
|
|||
|
|
|
|||
|
|
任务:
|
|||
|
|
|
|||
|
|
1. 扩展 `ResourceType`
|
|||
|
|
2. 新增 `GaussianSplat` 运行时资源类
|
|||
|
|
3. 设计 artifact header 与 section table
|
|||
|
|
4. 新增 `WriteGaussianSplatArtifactFile / LoadGaussianSplatArtifact`
|
|||
|
|
|
|||
|
|
验收标准:
|
|||
|
|
|
|||
|
|
1. `xcgsplat` 可写可读
|
|||
|
|
2. 资源元数据可稳定 roundtrip
|
|||
|
|
|
|||
|
|
### Phase 2:3DGS 专用 PLY importer 正式化
|
|||
|
|
|
|||
|
|
目标:
|
|||
|
|
|
|||
|
|
1. 把 `.ply` 纳入 `GaussianSplatImporter`
|
|||
|
|
|
|||
|
|
任务:
|
|||
|
|
|
|||
|
|
1. 新增 header parser
|
|||
|
|
2. 新增 3DGS property mapping
|
|||
|
|
3. 读取 room.ply 并转换成规范化内部 splat 数据
|
|||
|
|
4. 输出基础 cooked artifact
|
|||
|
|
|
|||
|
|
验收标准:
|
|||
|
|
|
|||
|
|
1. room.ply 可稳定导入
|
|||
|
|
2. 不依赖固定 struct stride == 文件 stride
|
|||
|
|
3. 错误路径有清晰日志
|
|||
|
|
|
|||
|
|
### Phase 3:AssetDatabase / Library / ResourceManager 接入
|
|||
|
|
|
|||
|
|
目标:
|
|||
|
|
|
|||
|
|
1. 把 `GaussianSplat` 完整接进项目资源工作流
|
|||
|
|
|
|||
|
|
任务:
|
|||
|
|
|
|||
|
|
1. `.ply -> GaussianSplatImporter`
|
|||
|
|
2. `EnsureArtifact(..., ResourceType::GaussianSplat)`
|
|||
|
|
3. `GaussianSplatLoader`
|
|||
|
|
4. `Load<GaussianSplat>()`
|
|||
|
|
|
|||
|
|
验收标准:
|
|||
|
|
|
|||
|
|
1. 可以通过 `Assets/.../room.ply` 正式加载
|
|||
|
|
2. cache hit 时不重走 source parse
|
|||
|
|
|
|||
|
|
### Phase 4:资源缓存与 GPU residency 预热骨架
|
|||
|
|
|
|||
|
|
目标:
|
|||
|
|
|
|||
|
|
1. 正式建立 3DGS GPU 资源缓存的边界
|
|||
|
|
|
|||
|
|
任务:
|
|||
|
|
|
|||
|
|
1. 设计 `CachedGaussianSplat`
|
|||
|
|
2. 建立 GPU residency 状态机
|
|||
|
|
3. 实现最小 GPU 资源构建 smoke path
|
|||
|
|
4. 明确禁止 draw path 首次同步上传
|
|||
|
|
|
|||
|
|
验收标准:
|
|||
|
|
|
|||
|
|
1. room.ply 对应的 `GaussianSplat` 可以被 GPU cache 预热成 ready 状态
|
|||
|
|
2. 资源层与渲染层边界清晰
|
|||
|
|
|
|||
|
|
### Phase 5:测试补齐与收口
|
|||
|
|
|
|||
|
|
目标:
|
|||
|
|
|
|||
|
|
1. 让这条链路可回归、可持续演进
|
|||
|
|
|
|||
|
|
任务:
|
|||
|
|
|
|||
|
|
1. 补全 importer / loader / cache hit / reimport 单测与集成测试
|
|||
|
|
2. 输出阶段性说明
|
|||
|
|
3. 为后续 renderer 接入保留唯一正式资源路径
|
|||
|
|
|
|||
|
|
验收标准:
|
|||
|
|
|
|||
|
|
1. room.ply 全链路测试稳定
|
|||
|
|
2. 不存在“临时直接读 ply”的旁路
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 13. 明确不允许出现的临时方案
|
|||
|
|
|
|||
|
|
以下方案本轮禁止出现:
|
|||
|
|
|
|||
|
|
1. 为了尽快出图,先在 render pass 里直接解析 `.ply`
|
|||
|
|
2. 先做一个 `BinaryResource` 包 `.ply` 内容,后面再说
|
|||
|
|
3. 先把 `.ply` 当 `Mesh` 导入
|
|||
|
|
4. 把 3DGS 的 GPU buffer 直接挂在 `Material` 资源本体上作为持久化资产
|
|||
|
|
5. 首次 draw 时同步创建 `pos / other / sh / color` GPU 资源
|
|||
|
|
6. 把 `room.ply` 单独写死成特判
|
|||
|
|
|
|||
|
|
这些做法都会把本该正式化的主线重新拉回临时方案。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 14. 本轮完成标志
|
|||
|
|
|
|||
|
|
当以下条件同时成立时,这份计划才算完成:
|
|||
|
|
|
|||
|
|
1. `.ply` 已正式被 `GaussianSplatImporter` 接管
|
|||
|
|
2. `GaussianSplat` 已成为正式 `ResourceType`
|
|||
|
|
3. `room.ply` 能稳定导入成 `xcgsplat`
|
|||
|
|
4. `ResourceManager` 能正式加载 `GaussianSplat`
|
|||
|
|
5. 二次加载能稳定命中 artifact
|
|||
|
|
6. GPU residency cache 骨架已经建立,不允许首次 draw 同步补做
|
|||
|
|
7. 资源层与缓存层测试已经覆盖 room.ply 主路径
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 15. 一句话结论
|
|||
|
|
|
|||
|
|
这条主线的第一步不是“做一个 ply 读取器”,而是把 3DGS 正式升级为引擎里的 `GaussianSplat` 资源体系:
|
|||
|
|
由 `GaussianSplatImporter` 把 `.ply` 转成 `xcgsplat` cooked artifact,由 `GaussianSplatLoader` 与 `ResourceManager` 正式接管加载,再由独立的 GPU residency cache 提前完成资源预热,为后续 3DGS 渲染 pass 提供唯一、稳定、无旁路的正式输入。
|