IO 模块
IO 模块充当 Visionary 的 统一数据摄入层。它处理多种 3D 高斯泼溅 (Gaussian Splatting) 格式和标准 3D 网格格式的文件加载与数据解析。它提供了一个灵活、可扩展的架构,用于加载各种文件格式并将它们转换为 GPU 就绪的数据结构。
概览
IO 模块是 3D 高斯泼溅管道中所有数据加载操作的入口点。它将原始文件数据转换为针对 WebGPU 渲染优化的结构化格式,将各种文件格式的复杂性抽象为一致的内存布局 (DataSource),应用程序无需了解底层文件结构即可使用。
关键特性
- 通用文件加载: 自动格式检测并委托给合适的加载器
- 多种高斯格式: 支持 PLY, SPZ, KSplat, SPLAT, SOG, 和 Compressed PLY
- Three.js 网格支持: 通过适配器处理 FBX, GLTF, OBJ, STL, 和 Mesh PLY
- 智能路由: 基于文件扩展名、MIME 类型或二进制“魔数字节 (Magic Bytes)”嗅探自动选择正确的加载器
- PLY 格式区分: 通过检查头部属性自动检测 PLY 文件是 3DGS 还是网格格式
- 格式检测: 用于格式识别的辅助函数 (
detectGaussianFormat,isGaussianFormat) - 进度报告: 带有特定阶段反馈的详细加载进度
- 内存优化: 使用半精度打包进行高效数据转换
- 可扩展架构: 带有双注册表(高斯和 Three.js)的插件式加载器注册系统
- 错误处理: 全面的验证和描述性错误消息
- 场景保存: 统一的场景导出功能 (
saveUnifiedScene)
核心概念
- 数据源 (Data Sources): 无论源格式如何,数据的标准化接口 (
DataSource,GaussianDataSource,ThreeJSDataSource) - 加载器注册表: 不同文件格式解析器(高斯和 Three.js)的动态注册系统
- 双注册表系统: 分别用于高斯泼溅格式和 Three.js 网格格式的注册表
- 格式检测: 通过扩展名、MIME 类型或魔数自动识别格式
- 进度回调: 长时间运行的加载操作期间的用户反馈
- 缓冲区管理: 高效的 CPU 到 GPU 数据传输准备
- 类型守卫: 安全的类型检查 (
isGaussianDataSource,isThreeJSDataSource)
快速开始
基本文件加载 (通用加载器)
import { defaultLoader } from 'src/io';
// 从文件输入加载 - 自动检测格式
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', async (event) => {
const file = event.target.files[0];
try {
const data = await defaultLoader.loadFile(file, {
onProgress: (progress) => {
console.log(`${progress.stage}: ${progress.progress * 100}%`);
}
});
// 检查是否为高斯数据
if (isGaussianDataSource(data)) {
console.log(`Loaded ${data.numPoints()} points`);
console.log(`SH degree: ${data.shDegree()}`);
} else if (isThreeJSDataSource(data)) {
console.log(`Loaded ${data.modelType()} model`);
}
} catch (error) {
console.error('Loading failed:', error);
}
});
加载不同格式
import { defaultLoader, detectGaussianFormat, isGaussianFormat } from 'src/io';
// 从文件名检测格式
const format = detectGaussianFormat('model.spz');
console.log(`Format: ${format}`); // 'spz'
// 检查文件是否为高斯格式
if (isGaussianFormat('model.ply')) {
const data = await defaultLoader.loadFile(file);
}
// 加载特定格式
import { SPZLoader } from 'src/io';
const spzLoader = new SPZLoader();
const data = await spzLoader.loadUrl('/models/scene.spz');
从 URL 加载
import { defaultLoader } from 'src/io';
const data = await defaultLoader.loadUrl('/models/scene.ply', {
isGaussian: true, // 如果格式不明确,显式指定
onProgress: ({ stage, progress, message }) => {
updateProgressBar(progress);
setStatusText(`${stage}: ${message || ''}`);
}
});
自定义加载器注册
import { createUniversalLoader, LoaderType } from 'src/io';
const loader = createUniversalLoader();
// 注册自定义高斯格式加载器
class CustomGaussianLoader implements ILoader<GaussianDataSource> {
// ... 实现
}
loader.register(new CustomGaussianLoader(), ['.custom'], LoaderType.GAUSSIAN);
// 注册自定义 Three.js 适配器
loader.register(new CustomThreeJSAdapter(), ['.custom'], LoaderType.THREE);
场景保存
import { saveUnifiedScene } from 'src/io/unified-scene-saver';
// 保存包含模型和关键帧的场景
await saveUnifiedScene({
scenes: [{
models: [
{
id: 'model-1',
name: 'MyModel.ply',
typeTag: 'fileModel',
trs: [[0, 0, 0], [0, 0, 0, 1], [1, 1, 1]],
originFile: fileHandle,
assetName: 'MyModel.ply'
}
],
keyframes: [
{
objectId: 'model-1',
frame: 0,
trs: [[0, 0, 0], [0, 0, 0, 1], [1, 1, 1]]
}
]
}],
folderHandle: directoryHandle,
meta: {
createdAt: new Date().toISOString(),
author: 'User'
}
});
模块结构
src/io/
├── index.ts # 接口、类型和导出
├── universal_loader.ts # 通用加载器 (高斯 + Three.js)
├── universal_gaussian_loader.ts # 仅高斯加载器
├── ply_loader.ts # PLY 格式实现
├── spz_loader.ts # SPZ 格式实现
├── ksplat_loader.ts # KSplat 格式实现
├── splat_loader.ts # SPLAT 格式实现
├── sog_loader.ts # SOG 格式实现
├── compressed_ply_loader.ts # 压缩 PLY 实现
├── GaussianData.ts # PLYGaussianData 类
├── threejs_adapters.ts # Three.js 网格格式适配器
└── unified-scene-saver.ts # 场景保存功能
数据流
- 文件输入 → 通用加载器检测格式
- 格式检测 → 选择合适的加载器(高斯或 Three.js 注册表)
- PLY 格式区分 → 对于
.ply文件,检查头部以确定是 3DGS 还是网格 - 解析 → 解析原始数据并报告进度
- 处理 → 将数据转换为 GPU 格式
- 输出 → 准备好进行渲染的
GaussianDataSource或ThreeJSDataSource
支持的格式
高斯泼溅格式
| 格式 | 扩展名 | 加载器类 | 描述 |
|---|---|---|---|
| 标准 PLY | .ply |
PLYLoader |
标准 3DGS 格式 (ASCII/Binary)。执行归一化和 SH 打包。通过检查头部中的 3DGS 属性自动检测。 |
| 压缩 PLY | .compressed.ply |
CompressedPLYLoader |
使用基于分块的量化压缩的 PLY 格式。位置、旋转、缩放和颜色使用量化打包。通过 .compressed.ply 扩展名检测。 |
| SPZ | .spz |
SPZLoader |
带有量化位置/旋转的基于 GZIP 的容器。 |
| SOG | .sog |
SOGLoader |
SuperOrdered Gaussians。支持原始 (Raw) 和 ZIP 压缩变体。通过 ZIP 魔数 (0x504b0304) 检测。 |
| Splat | .splat |
SplatLoader |
原始二进制转储格式(32 字节步长)。加载极快。 |
| KSplat | .ksplat |
KSplatLoader |
Luma AI 优化的块格式。通过 "KSPL" 魔数检测。 |
网格格式 (Three.js 适配器)
| 格式 | 扩展名 | 适配器类 | 描述 |
|---|---|---|---|
| FBX | .fbx |
FBXLoaderAdapter |
包装 THREE.FBXLoader。保留材质并应用阴影设置。 |
| GLTF/GLB | .gltf, .glb |
GLTFLoaderAdapter |
包装 THREE.GLTFLoader。保留材质并应用阴影设置。 |
| OBJ | .obj |
OBJLoaderAdapter |
包装 THREE.OBJLoader。支持 MTL 材质。 |
| STL | .stl |
STLLoaderAdapter |
包装 THREE.STLLoader。 |
| 网格 PLY | .ply |
ThreeJSPLYLoaderAdapter |
用于包含传统三角网格的 PLY 文件(当 3DGS 属性缺失时检测到)。 |
加载器类型
UniversalLoader
处理高斯泼溅和 Three.js 网格格式的主加载器。它维护两个独立的注册表,并根据格式检测智能路由文件。
特性:
- 双注册表系统(高斯和 Three.js)
- 自动 PLY 格式区分(3DGS 与网格)
- 压缩格式的魔数检测
- 运行时加载器注册
UniversalGaussianLoader
仅处理高斯泼溅格式的专用加载器。当您知道只处理高斯数据时很有用。
特性:
- 单一用途:仅限高斯格式
- 更简单的 API 表面
- 更快的格式检测(无需查询 Three.js 注册表)
格式检测
IO 模块提供了几个用于格式检测的工具:
import {
detectGaussianFormat,
isGaussianFormat,
GaussianFormat,
isGaussianDataSource,
isThreeJSDataSource
} from 'src/io';
// 从文件名检测格式
const format = detectGaussianFormat('model.spz'); // 返回 GaussianFormat.SPZ
// 检查文件是否为高斯格式
if (isGaussianFormat('model.ply')) {
// 处理高斯文件
}
// 用于运行时类型检查的类型守卫
if (isGaussianDataSource(data)) {
const points = data.numPoints();
}
if (isThreeJSDataSource(data)) {
const obj = data.object3D();
}
PLY 格式区分
该模块通过检查头部是否包含必需的 3DGS 属性,自动检测 .ply 文件是 3D 高斯泼溅文件还是传统网格文件:
property float opacityproperty float scale_0,scale_1,scale_2property float rot_0,rot_1,rot_2,rot_3
如果所有这些属性都存在,文件将被视为 3DGS 文件;否则,它将被路由到 Three.js PLY 加载器。
性能特征
- 加载速度: 针对大型数据集(>100万点)进行了优化
- 内存使用: 高效的半精度打包将 GPU 内存减少了 50%
- 进度粒度: 亚秒级更新,实现响应式 UI
- 错误恢复: 优雅地处理格式错误的文件
- 流式处理: 大文件增量处理以避免阻塞
集成点
IO 模块与以下模块集成:
- App 模块: 被
FileLoader管理器使用,用于统一资源加载 - Point Cloud 模块: 为 GPU 缓冲区创建提供数据
- Renderer: 提供预处理的高斯参数
- Utils: 半精度转换和数学工具