空间产品工程商业项目· 数据转换管线系
3DGS 与 Mesh 数据转换管线
一组部署在后端 Worker 上的数据加工 CLI,把重建产出的 PLY、OBJ 转换为各查看器可流式消费的标准产物,并以内存与体积指标验证效果。
- Node.js 22
- TypeScript
- splat-transform 3.4
- gltf-transform
- Draco
- xatlas
- sharp
- Worker Threads
- 我的角色
- 管线架构与核心算法实现(流式读写、LOD、碰撞、3D Tiles 纹理重烘焙)
- 材料说明
- 项目资料与交付记录
- 轴向校正流式处理的输入与峰值内存
- 4.1 GiB → ~220 MB
- 220 MB+ OBJ 产出 3D Tiles 体积(对比 Cesium Ion 基准)
- 34.1 MB → 20.7 MB
- LOD 清洗阶段的恒定缓冲,双遍流式不随文件增大
- 16 MB
其余 1 项指标与口径
- LOD 清洗阶段的恒定缓冲,双遍流式不随文件增大
- 16 MB
背景问题
三维重建的输出体积大、格式各异:数 GB 的 PLY 无法整体装入内存,单体 OBJ 带有大量高分辨率碎纹理,直接加载会在浏览器中 OOM。查看器需要的是分块、分级、带碰撞数据的标准产物。
约束
- 管线运行在后端 Worker 上,需要支持多机部署与固定依赖版本。
- 输入规模远超内存,峰值内存必须与文件大小解耦。
- 产物要能被 PlayCanvas 查看器与 CesiumJS 直接使用。
架构
公司数据加工链(后端 Worker CLI)
[轴向校正 CLI] PLY Z-up → Y-up(流式,4 GiB 级输入)
│
▼
[LOD 转换 CLI] Morton 预排序 → 50% 逐级抽稀 → Streamed SOG(lod-meta.json)
│
[碰撞生成 CLI] 分位裁剪 → 稀疏八叉树体素 → voxel.json / .bin(或 GLB 碰撞网格)
[OBJ→3D Tiles 管线] 八叉树分割 → LOD 简化 → 纹理重烘焙 → Draco 压缩 → 3D Tiles 1.1
关键决策与取舍
- 流式而非整体加载:轴向校正只解析 PLY 头,按块读取、旋转与写出;LOD 清洗使用 16 MB 缓冲零拷贝扫描,发现 NaN 或 Infinity 时写出剔除后的临时副本,原文件保持只读。
- 分位裁剪替代正态近似:室外场景的远景漂浮点会让正态近似误裁建筑边缘,并使包围盒膨胀。改为预过滤半透明噪点后直接取坐标的实际百分位边界。
- 纹理重烘焙:180 余张高分辨率纹理做图集会直接 OOM,且父级瓦片跨多个材质无法合并。每个瓦片按需加载源纹理,烘焙到自适应分辨率的单张图,用完即释放。
- 以第三方标准工具为中枢:瓦片集的组装与优化全部委托 3d-tiles-tools,不手写 JSON。
- 原子写:输出先写临时文件、刷盘后再重命名,中断只会留下可删除的临时文件。
结果
- 4.1 GiB 输入的轴向校正峰值约 220 MB,与文件大小无关。
- 220 MB 量级的 OBJ 与 180 张纹理的测试集,产出 94 个含纹理瓦片,Draco 压缩率 81.6%,总体积 20.7 MB,低于 Cesium Ion 基准的 34.1 MB。
- 体积过大或过小的碰撞体会主动告警,避免静默产出无效数据。
我的职责
- 管线整体架构与各阶段接口定义。
- 流式文件系统适配层、LOD 生成与碰撞体素化的实现。
- OBJ→3D Tiles 管线 的八叉树分割、纹理重烘焙与瓦片装配。