跳转至

IO 模块 API 参考手册

本文档涵盖了 IO 模块暴露的所有公共接口。它沿袭了 SparkJS 的风格:介绍概念,展示签名,并解释其如何融入更广泛的高斯泼溅(Gaussian Splatting)管道中。

目录


核心接口

DataSource

任何提供 3D 模型元数据的数据源的标准契约。

interface DataSource {
  bbox(): { min: [number, number, number]; max: [number, number, number] };
  center?: [number, number, number];
  up?: [number, number, number] | null;
  kernelSize?: number;
  mipSplatting?: boolean;
  backgroundColor?: [number, number, number];
}

GaussianDataSource

专门针对高斯泼溅的 DataSource,独立于原始文件格式。

interface GaussianDataSource extends DataSource {
  gaussianBuffer(): ArrayBuffer;
  shCoefsBuffer(): ArrayBuffer;
  numPoints(): number;
  shDegree(): number;
}
  • gaussianBuffer() – 打包的泼溅参数,以半精度浮点数存储(每个点 10 个 uint16 值)。
  • shCoefsBuffer() – 交错存储的球谐函数系数(每个 uint32 中存储两个 f16)。
  • numPoints() – 泼溅点总数。
  • shDegree() – 球谐函数阶数;每个通道有 (degree + 1)^2 个系数。

ThreeJSDataSource

用于加载器的适配器,除了模型数据外,还提供 Three.js 对象。

interface ThreeJSDataSource extends DataSource {
  object3D(): any;            // THREE.Object3D
  modelType(): string;
}

ILoader<T>

通用的文件加载器契约。

interface ILoader<T extends DataSource = DataSource> {
  loadFile(file: File, options?: LoadingOptions): Promise<T>;
  loadUrl(url: string, options?: LoadingOptions): Promise<T>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<T>;
  canHandle(filename: string, mimeType?: string): boolean;
  getSupportedExtensions(): string[];
}

LoadingOptions 通常包含进度回调和取消信号。

LoaderRegistry

将文件扩展名映射到加载器的动态注册表。

interface LoaderRegistry {
  register<T extends DataSource>(loader: ILoader<T>, extensions: string[]): void;
  getLoader(filename: string, mimeType?: string): ILoader | null;
  getAllSupportedExtensions(): string[];
}

通用加载器

入口点

function createUniversalLoader(): UniversalLoader;
const defaultLoader: UniversalLoader;
  • createUniversalLoader() – 构建一个独立的注册表实例。
  • defaultLoader – App 层使用的共享单例。

UniversalLoader 表面

class UniversalLoader implements ILoader, LoaderRegistry {
  constructor();

  // ILoader 接口
  loadFile(file: File, options?: LoadingOptions): Promise<DataSource>;
  loadUrl(url: string, options?: LoadingOptions): Promise<DataSource>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<DataSource>;
  canHandle(filename: string, mimeType?: string, options?: { isGaussian?: boolean }): boolean;
  getSupportedExtensions(): string[];

  // LoaderRegistry 接口
  register<T extends DataSource>(loader: ILoader<T>, extensions: string[], type: LoaderType): void;
  getLoader(filename: string, mimeType?: string, options?: { isGaussian?: boolean }): ILoader | null;
  getAllSupportedExtensions(): string[];

  // 额外方法
  async getLoaderForFile(file: File, mimeType?: string): Promise<ILoader | null>;
}

LoaderType 枚举:

enum LoaderType {
  GAUSSIAN = 'gaussian',
  THREE = 'three'
}

格式检测管道

  1. 检查文件扩展名/MIME 类型。
  2. 检查显式的 options.isGaussian 提示。
  3. 对于 .ply 文件,读取头部以检测 3DGS 属性。
  4. 检查压缩格式(GZIP, ZIP, KSPL)的魔数(magic bytes)。
  5. 定位第一个声明支持该格式的已注册加载器。
  6. 以流的方式传输数据并更新进度({ stage, progress, message? })。
  7. 将结果归一化为 DataSource

进度报告

LoadingOptions 接受:

interface LoadingOptions {
  signal?: AbortSignal;
  onProgress?: (progress: LoadingProgress) => void;
  debug?: boolean;
  isGaussian?: boolean;  // 显式格式提示
}

interface LoadingProgress {
  stage: 'fetch' | 'parse' | 'pack' | string;
  progress: number;          // 0..1
  message?: string;
}

高斯格式加载器

PLYLoader

处理 ASCII 和二进制 PLY 泼溅数据。

class PLYLoader implements ILoader<PLYGaussianData> {
  loadFile(file: File, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadUrl(url: string, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<PLYGaussianData>;
  canHandle(filename: string): boolean;
  getSupportedExtensions(): string[]; // ['.ply']
}

主要行为:

  • 自动检测 ASCII 与二进制负载(小端和大端)。
  • 解析高斯特定的顶点属性(位置、不透明度、SH 系数、协方差)。
  • 当头部或属性缺失时发出明确的错误。
  • 流式处理大文件以避免阻塞主线程。
  • 执行归一化、四元数转换和 SH 打包。

CompressedPLYLoader

处理压缩的 PLY 文件。

class CompressedPLYLoader implements ILoader<PLYGaussianData> {
  loadFile(file: File, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadUrl(url: string, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<PLYGaussianData>;
  canHandle(filename: string): boolean;
  getSupportedExtensions(): string[]; // ['.compressed.ply']
}

主要行为:

  • 在使用标准 PLY 加载器解析之前进行解压。
  • 支持文件和 URL 加载。

SPZLoader

处理 SPZ(基于 GZIP 的容器)格式。

class SPZLoader implements ILoader<PLYGaussianData> {
  loadFile(file: File, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadUrl(url: string, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<PLYGaussianData>;
  canHandle(filename: string): boolean;
  getSupportedExtensions(): string[]; // ['.spz']
}

主要行为:

  • GZIP 压缩容器格式。
  • 处理量化后的位置/旋转。
  • 针对较小的文件大小进行了优化。

KSplatLoader

处理 Luma AI 的 KSplat 格式。

class KSplatLoader implements ILoader<PLYGaussianData> {
  loadFile(file: File, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadUrl(url: string, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<PLYGaussianData>;
  canHandle(filename: string): boolean;
  getSupportedExtensions(): string[]; // ['.ksplat']
}

主要行为:

  • 检测 "KSPL" 魔数(前 4 个字节)。
  • Luma AI 优化的块格式。
  • 快速加载,解析开销极小。

SplatLoader

处理原始二进制 SPLAT 格式。

class SplatLoader implements ILoader<PLYGaussianData> {
  loadFile(file: File, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadUrl(url: string, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<PLYGaussianData>;
  canHandle(filename: string): boolean;
  getSupportedExtensions(): string[]; // ['.splat']
}

主要行为:

  • 原始二进制转储格式(每个点 32 字节步长)。
  • 加载极快(无解析开销)。
  • 格式: [x, y, z, r, g, b, a, rot_0, rot_1, rot_2, rot_3, scale_0, scale_1, scale_2] (均为 float32)。

SOGLoader

处理 SuperOrdered Gaussians (SOG) 格式。

class SOGLoader implements ILoader<PLYGaussianData> {
  loadFile(file: File, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadUrl(url: string, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<PLYGaussianData>;
  canHandle(filename: string): boolean;
  getSupportedExtensions(): string[]; // ['.sog']
}

主要行为:

  • SuperOrdered Gaussians 格式。
  • 支持原始 (Raw) 和 ZIP 压缩变体。
  • 检测 ZIP 魔数 (0x504b0304)。
  • 处理分层高斯组织。

UniversalGaussianLoader

仅处理高斯泼溅格式的专用加载器。

class UniversalGaussianLoader implements ILoader<PLYGaussianData> {
  constructor();

  loadFile(file: File, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadUrl(url: string, options?: LoadingOptions): Promise<PLYGaussianData>;
  loadBuffer(buffer: ArrayBuffer, options?: LoadingOptions): Promise<PLYGaussianData>;
  canHandle(filename: string, mimeType?: string): boolean;
  getSupportedExtensions(): string[];
}

主要行为:

  • 单一用途:仅限高斯格式。
  • 更简单的 API 表面。
  • 更快的格式检测(无需查询 Three.js 注册表)。
  • 内部管理:PLY, SPZ, KSplat, SPLAT, SOG, Compressed PLY。

Three.js 适配器

ThreeJSModelData

实现 ThreeJSDataSource 接口的包装类。

class ThreeJSModelData implements ThreeJSDataSource {
  constructor(object3D: THREE.Object3D, modelType: string = 'unknown');

  object3D(): THREE.Object3D;
  modelType(): string;
  bbox(): { min: [number, number, number]; max: [number, number, number] };
}

GLTFLoaderAdapter

GLTF/GLB 格式适配器。

class GLTFLoaderAdapter extends ThreeJSLoaderAdapter<THREE.Group> {
  constructor();
  getSupportedExtensions(): string[]; // ['.gltf', '.glb']
  // ... 实现 ILoader<ThreeJSModelData>
}

主要行为:

  • 包装 THREE.GLTFLoader
  • 保留 GLTF 材质。
  • 自动应用阴影设置。
  • 支持进度报告。

OBJLoaderAdapter

OBJ 格式适配器。

class OBJLoaderAdapter extends ThreeJSLoaderAdapter<THREE.Group> {
  constructor();
  getSupportedExtensions(): string[]; // ['.obj']
  // ... 实现 ILoader<ThreeJSModelData>
}

主要行为:

  • 包装 THREE.OBJLoader
  • 支持 MTL 材质文件。
  • 应用阴影设置和回退材质。

FBXLoaderAdapter

FBX 格式适配器。

class FBXLoaderAdapter extends ThreeJSLoaderAdapter<THREE.Group> {
  constructor();
  getSupportedExtensions(): string[]; // ['.fbx']
  // ... 实现 ILoader<ThreeJSModelData>
}

主要行为:

  • 包装 THREE.FBXLoader
  • 保留 FBX 材质。
  • 应用阴影设置。

STLLoaderAdapter

STL 格式适配器。

class STLLoaderAdapter extends ThreeJSLoaderAdapter<THREE.Mesh> {
  constructor();
  getSupportedExtensions(): string[]; // ['.stl']
  // ... 实现 ILoader<ThreeJSModelData>
}

主要行为:

  • 包装 THREE.STLLoader
  • 创建带有回退材质的网格。
  • 应用阴影设置。

ThreeJSPLYLoaderAdapter

传统网格 PLY 格式适配器。

class ThreeJSPLYLoaderAdapter extends ThreeJSLoaderAdapter<THREE.Mesh> {
  constructor();
  getSupportedExtensions(): string[]; // ['.ply']
  // ... 实现 ILoader<ThreeJSModelData>
}

主要行为:

  • 包装 THREE.PLYLoader
  • 用于不包含 3DGS 属性的 PLY 文件。
  • 当 PLY 头部缺少 3DGS 属性时自动检测并使用。

createThreeJSAdapters

创建所有 Three.js 适配器的工厂函数。

function createThreeJSAdapters(): ThreeJSLoaderAdapter<any>[];

返回所有可用的 Three.js 加载器适配器数组。


数据容器

PLYGaussianData

所有高斯加载器返回的 GaussianDataSource 的具体实现。

class PLYGaussianData implements GaussianDataSource {
  constructor(args: {
    gaussianBuffer: ArrayBuffer;
    shBuffer: ArrayBuffer;
    numPoints: number;
    degree: number;
    bbox: { min: [number, number, number]; max: [number, number, number] };
    center?: [number, number, number];
    up?: [number, number, number] | null;
    kernelSize?: number;
    mipSplatting?: boolean;
    backgroundColor?: [number, number, number];
  });

  gaussianBuffer(): ArrayBuffer;
  shCoefsBuffer(): ArrayBuffer;
  numPoints(): number;
  shDegree(): number;
  bbox(): { min: [number, number, number]; max: [number, number, number] };
}

格式检测工具

GaussianFormat 枚举

enum GaussianFormat {
  PLY = 'ply',
  SPZ = 'spz',
  KSPLAT = 'ksplat',
  SPLAT = 'splat',
  SOG = 'sog',
  COMPRESSED_PLY = 'compressed.ply'
}

detectGaussianFormat

从文件名检测高斯格式。

function detectGaussianFormat(filename: string): GaussianFormat | null;

返回: 格式枚举,如果不是公认的高斯格式则返回 null

示例:

const format = detectGaussianFormat('model.spz'); // 返回 GaussianFormat.SPZ

isGaussianFormat

检查文件名是否具有支持的高斯格式。

function isGaussianFormat(filename: string): boolean;

返回: 如果文件名以支持的高斯扩展名结尾,则返回 true

getSupportedGaussianFormats

返回所有支持的高斯格式扩展名。

function getSupportedGaussianFormats(): string[];

返回: ['.ply', '.spz', '.ksplat', '.splat', '.sog', '.compressed.ply']

isGaussianDataSource

类型守卫,用于检查数据源是否为高斯数据。

function isGaussianDataSource(data: DataSource): data is GaussianDataSource;

返回: 指示数据是否为 GaussianDataSource 的类型谓词。

isThreeJSDataSource

类型守卫,用于检查数据源是否为 Three.js 模型。

function isThreeJSDataSource(data: DataSource): data is ThreeJSDataSource;

返回: 指示数据是否为 ThreeJSDataSource 的类型谓词。


场景保存

saveUnifiedScene

将场景结构和模型文件保存到目录中。

async function saveUnifiedScene(params: SaveUnifiedSceneParams): Promise<void>;

参数:

interface SaveUnifiedSceneParams {
  scenes: SaveUnifiedSceneSceneEntry[];
  folderHandle: FileSystemDirectoryHandle;
  meta?: any;
  cameraParams?: any;
  totalFrames?: number;
}

场景条目 (Scene Entry):

interface SaveUnifiedSceneSceneEntry {
  models: SaveUnifiedSceneModel[];
  keyframes?: SaveUnifiedSceneKeyframe[];
  view?: 'left' | 'right' | string;
  [k: string]: any;
}

模型 (Model):

interface SaveUnifiedSceneModel {
  id: string;
  name?: string;
  typeTag: string;
  trs: [number[], number[], number[]];
  type?: string;
  gaussianParams?: any;
  cameraParams?: any;
  params?: Record<string, any>;
  originFile?: File | Blob | FileSystemFileHandle;
  assetName?: string;
}

关键帧 (Keyframe):

interface SaveUnifiedSceneKeyframe {
  objectId: string;
  frame: number;
  trs: [number[], number[], number[]];
  gaussianParams?: any;
  cameraParams?: any;
}

主要行为:

  • 在保存前验证文件夹句柄权限。
  • 在写入前清空目标文件夹内容。
  • 复制所有模型文件(按名称去重)。
  • 生成包含场景结构的 scene.json
  • 优雅地处理 FileSystem API 错误。

示例:

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() }
});

类型定义

LoadingOptions

interface LoadingOptions {
  onProgress?: (progress: LoadingProgress) => void;
  signal?: AbortSignal;
  debug?: boolean;
  isGaussian?: boolean;  // 显式格式提示
}

LoadingProgress

interface LoadingProgress {
  stage: 'fetch' | 'parse' | 'pack' | string;
  progress: number;          // 0..1
  message?: string;
}

LoaderType

enum LoaderType {
  GAUSSIAN = 'gaussian',
  THREE = 'three'
}

错误处理

IO 模块抛出类型化错误,以便调用者可以提供可操作的反馈。

错误 描述 建议操作
UnsupportedFormatError 没有加载器接受该文件扩展名/MIME 类型。 提示用户选择支持的格式或安装扩展加载器。
MalformedPLYHeaderError 头部缺少必需的属性。 验证资源是否使用 Visionary / Spark 兼容工具导出。
PLYStreamError 二进制负载意外结束。 建议重新下载/重新导出资源。
AbortError 通过 AbortController 中止了加载。 静默取消;通常由用户发起。
FolderHandleError FileSystem 文件夹句柄无效或权限被拒绝。 请求新的文件夹句柄或检查权限。

所有错误都继承自 IOError,它添加了 stage?: ProgressStage 以提供更丰富的遥测数据。

class IOError extends Error {
  constructor(message: string, options?: { stage?: ProgressStage; cause?: unknown });
  stage?: ProgressStage;
}

集成检查清单

  • 在 App 模块内使用 defaultLoader;它已经注册了所有支持的格式。
  • 在引导期间尽早注册自定义加载器,以便它们参与检测。
  • 加载大型资源时始终提供 onProgress,以保持 UI 响应。
  • 当格式不明确时(例如 .ply 文件),显式使用 isGaussian 选项。
  • 与预处理共享辅助函数(打包、边界、元数据提取),以避免重复计算。
  • 处理 AbortSignal 以响应用户发起的取消。
  • 使用类型守卫(isGaussianDataSource, isThreeJSDataSource)进行运行时类型检查。