Skip to content

Models Module Architecture

概览

Models 模块为 Visionary 中的所有模型类型提供数据层。它定义了统一的接口,适用于高斯 Splatting 格式 (PLY, SPZ, KSplat, SPLAT, SOG, Compressed PLY)、ONNX 动态模型和 FBX 网格文件。该模块由接口驱动,并在运行时状态和 UI 友好快照之间进行了清晰的分离。

Model Interfaces (ModelEntry, ModelInfo)
├── ModelManager (位于 app/managers) - 注册表, 查找, 可见性
├── FileLoader (位于 app/managers) - IO 管道, 格式检测
├── ONNXManager (位于 app/managers) - ONNX 模型生命周期
└── Wrappers (FBXModelWrapper) - 特定格式的功能

核心接口

ModelEntry

已加载模型的运行时表示。包含对 pointCloud/object3D 的完整引用以及所有元数据。

interface ModelEntry {
  id: string;                                    // 唯一标识符(自动生成)
  name: string;                                   // 显示名称
  visible: boolean;                               // 渲染可见性标志
  pointCloud: PointCloud | DynamicPointCloud | FBXModelWrapper;  // 特定格式的数据
  pointCount: number;                             // 总点数/顶点数
  isDynamic: boolean;                             // 对 ONNX 模型为 true
  modelType: ModelType;                           // 格式类型
  colorMode?: 'sh' | 'rgb';                       // 颜色编码模式
  colorChannels?: number;                         // 颜色通道数
}

关键点: - pointCloud 可以是 PointCloud (静态高斯), DynamicPointCloud (ONNX), 或 FBXModelWrapper (FBX 网格) - modelType 支持:'ply' | 'spz' | 'ksplat' | 'splat' | 'sog' | 'compressed.ply' | 'onnx' | 'fbx' - isDynamic 区分流式点云 (ONNX) 和静态资产 - colorModecolorChannels 允许 UI 一致地显示颜色元数据

ModelInfo

用于 UI 层的轻量级、只读快照。不包含 pointCloud 引用,以避免持有大型对象图。

interface ModelInfo {
  id: string;
  name: string;
  visible: boolean;
  pointCount: number;
  isDynamic: boolean;
  modelType: ModelType;
  colorMode?: 'sh' | 'rgb';
  colorChannels?: number;
}

用例: React 渲染、UI 列表和序列化安全。ModelManager.getModels() 返回 ModelInfo[] 供 UI 使用。

ModelType

所有支持的模型格式的联合类型:

type ModelType = 
  | 'ply' | 'spz' | 'ksplat' | 'splat' | 'sog' | 'compressed.ply'  // 高斯格式
  | 'onnx'                                                          // 动态 ONNX
  | 'fbx';                                                          // FBX 网格

与 Managers 的集成

Models 模块接口被 app/managers 模块中的 managers 使用:

ModelManager 集成

ModelManager (位于 app/managers) 使用 ModelEntryModelInfo

  • 维护一个 ModelEntry 实例数组
  • 提供 getModels(): ModelInfo[] 供 UI 使用
  • 提供 getFullModels(): ModelEntry[] 用于调试/测试
  • 处理模型注册、移除和查询
  • 跟踪可见性、容量限制和统计信息

FileLoader 集成

FileLoader (位于 app/managers) 创建 ModelEntry 实例:

  • 加载高斯格式 (PLY, SPZ, KSplat, SPLAT, SOG, Compressed PLY) → 创建带有 PointCloudModelEntry
  • 加载 FBX 文件 → 创建带有 FBXModelWrapperModelEntry
  • 使用 ModelManager.addModel() 注册条目

ONNXManager 集成

ONNXManager (位于 app/managers) 创建动态模型条目:

  • 加载 ONNX 模型 → 创建带有 DynamicPointCloudModelEntry
  • 将 ONNX 条目设置为 isDynamic: true
  • 管理 ONNX 生成器生命周期

FBXModelWrapper

FBXModelWrapper 类包装 Three.js FBX 资产并实现 ITimelineTarget 以进行 timeline 集成。

特性

  • Three.js 集成: 包装 THREE.GroupTHREE.AnimationMixer
  • 动画支持: 完全的动画控制(播放、暂停、停止、速度、时间)
  • Timeline 集成: 实现 ITimelineTarget 接口
  • 变换支持: 带有 setTransform() 方法的 4x4 变换矩阵
  • 可见性控制: setVisible() / getVisible() 方法
  • 顶点计数: getVertexCount() 用于统计

动画控制

class FBXModelWrapper implements ITimelineTarget {
  // Timeline 接口
  setAnimationTime(time: number): void;
  setAnimationSpeed(speed: number): void;
  getAnimationSpeed(): number;
  startAnimation(speed?: number): void;
  pauseAnimation(): void;
  resumeAnimation(): void;
  stopAnimation(): void;
  setTimeScale(scale: number): void;
  setTimeOffset(offset: number): void;
  setTimeUpdateMode(mode: 'fixed_delta' | 'variable_delta'): void;
  getCurrentTime(): number;
  update(deltaTime: number): void;

  // 动画管理
  switchToClip(clipIndex: number): boolean;
  getClipInfo(): Array<{name: string, duration: number}>;
  supportsAnimation(): boolean;
}

FBXLoadOptions

interface FBXLoadOptions {
  autoPlay?: boolean;        // 自动播放第一个动画
  defaultSpeed?: number;      // 默认播放速度
  loop?: boolean;             // 循环动画
  blendMode?: 'normal' | 'additive';  // 动画混合模式
}

Wrappers (包装器)

  • FBXModelWrapper – 加载 FBX 资产,暴露材质、动画和层级实用工具。
  • 其他包装器遵循相同的模式用于 GLTF, OBJ, ONNX 派生模型等。
  • 包装器可以暴露便捷方法(播放动画、重载纹理),同时保持基本契约不变。

数据流

加载流程

  1. 文件输入FileLoader.loadFile()FileLoader.loadSample()
  2. 格式检测 → 检测格式 (Gaussian, ONNX, FBX)
  3. 数据加载 → 使用 IO 模块的 defaultLoaderFBXLoaderManager
  4. ModelEntry 创建 → 创建带有适当 pointCloudwrapperModelEntry
  5. 注册ModelManager.addModel() 注册条目
  6. UI 更新ModelManager.getModels() 返回 ModelInfo[] 给 UI

ONNX 流程

  1. ONNX 加载ONNXManager.loadONNXModel()
  2. DynamicPointCloud 创建 → 使用 ONNX 生成器创建 DynamicPointCloud
  3. ModelEntry 创建 → 创建带有 isDynamic: trueModelEntry
  4. 注册ModelManager.addModel() 注册条目
  5. 动画更新AnimationManager 每帧更新动态模型

FBX 流程

  1. FBX 加载FBXLoaderManager.loadFromFile()
  2. FBXModelWrapper 创建 → 创建带有动画混合器的包装器
  3. ModelEntry 创建 → 创建带有 FBXModelWrapperModelEntry
  4. 注册ModelManager.addModel() 注册条目
  5. 动画控制 → Timeline 或直接动画方法控制播放

可扩展性

添加新格式

  1. 扩展 ModelType: 在 ModelType 联合类型中添加新格式
  2. 创建 Loader: 在 app/managers 中实现加载器(或使用 IO 模块)
  3. 创建 Wrapper (可选): 如果格式需要特殊处理,创建包装器类
  4. 更新 FileLoader: 添加格式检测和加载逻辑
  5. 测试: 确保 ModelEntry 创建工作正常

示例:添加 GLTF 支持

// 1. 扩展 ModelType
type ModelType = ... | 'gltf' | 'glb';

// 2. 创建 wrapper (如果需要)
class GLTFModelWrapper {
  // ... 实现
}

// 3. 更新 ModelEntry pointCloud 类型
pointCloud: PointCloud | DynamicPointCloud | FBXModelWrapper | GLTFModelWrapper;

// 4. 更新 FileLoader 以处理 .gltf/.glb

性能与内存

  • ModelEntry 持有完整的 pointCloud 引用(用于运行时操作)
  • ModelInfo 是轻量级的(用于 UI 列表和序列化)
  • 销毁: 移除模型时,对包装器和点云调用 dispose()
  • 容量限制: ModelManager 强制执行最大模型数量(默认 10000)
  • 统计: 跟踪点数和可见性以进行性能监控

最佳实践

  1. UI 使用 ModelInfo: React 组件和 UI 列表优先使用 ModelInfo
  2. 操作使用 ModelEntry: 当需要 pointCloud 引用时使用 ModelEntry
  3. 类型守卫: 访问动态特定功能前检查 isDynamic
  4. 格式检测: 使用 modelType 确定可用操作
  5. 内存管理: 移除模型时务必销毁包装器和点云

此架构使模型摄取保持可预测性,同时保持足够的灵活性以适应复杂的管道(混合格式、动态 ONNX 内容、FBX 动画和编辑器工具)。