Manager 架构
本文档描述了现在支撑应用程序的基于 Manager 的架构。单一的单体 App 已被拆分为多个专注的 Manager,从而极大地提高了模块化、可测试性和可扩展性。
概览
基于 Manager 的架构将单体 App 类拆分为专注、可测试的 Manager:
App (编排者/外观)
├── ModelManager # 模型存储和元数据
├── FileLoader # 多格式文件加载 (Gaussian + FBX)
├── GaussianLoader # 高级 GaussianModel 创建服务
├── ONNXManager # ONNX 模型生命周期和推理
├── FBXLoaderManager # FBX 网格文件加载
├── CameraManager # 相机和控制器管理
├── AnimationManager # 动态模型更新
└── RenderLoop # 帧循环和渲染协调
每个 Manager 拥有特定的职责,而 App 通过依赖注入将它们连接起来。Manager 之间通过定义良好的接口和回调进行通信。
核心 Managers
ModelManager
职责:维护所有已加载的模型并暴露统一的接口。
亮点: - 存储元数据和引用。 - 跟踪可见性、变换和容量限制。 - 支持 PLY 和 ONNX 条目。 - 生成唯一名称并加速查找。
关键方法:
class ModelManager {
addModel(model: Omit<ModelEntry, 'id'>): ModelEntry;
removeModel(id: string): boolean;
getModels(): ModelInfo[];
getModelWithPointCloud(type: 'ply' | 'onnx', id?: string): ModelEntry | null;
getFullModels(): ModelEntry[];
getModelsByType(modelType: 'ply' | 'onnx'): ModelEntry[];
getVisibleModels(): ModelEntry[];
getDynamicModels(): ModelEntry[];
setModelVisibility(id: string, visible: boolean): boolean;
getModelCount(): number;
getTotalPoints(): number;
getTotalVisiblePoints(): number;
isAtCapacity(): boolean;
getRemainingCapacity(): number;
clearAllModels(): void;
findModelByName(name: string): ModelEntry | null;
generateUniqueName(baseName: string): string;
hasModelWithName(name: string): boolean;
// 旧版变换助手
setModelPosition(id: string, x: number, y: number, z: number): boolean;
setModelRotation(id: string, x: number, y: number, z: number): boolean;
setModelScale(id: string, scale: number | [number, number, number]): boolean;
setModelTransform(id: string, transform: Float32Array | number[]): boolean;
getModelPosition(id: string): [number, number, number] | null;
getModelTransform(id: string): Float32Array | null;
}
FileLoader
职责:加载并解析多种高斯格式和 FBX 文件。
特性:
- 内部使用 IO 模块的 defaultLoader 进行统一格式处理
- 支持所有高斯格式:PLY, SPZ, KSplat, SPLAT, SOG, Compressed PLY
- 通过 FBXLoaderManager 支持 FBX 网格文件
- 通过 detectGaussianFormat() 和 isGaussianFormat() 进行自动格式检测
- 支持带进度回调的文件和 URL 加载
- 处理带有格式检测的 Blob URL
- 在加载前验证容量限制
class FileLoader {
loadFile(file: File, device: GPUDevice): Promise<ModelEntry | null>;
loadSample(filename: string, device: GPUDevice, expectedType?: string): Promise<ModelEntry | null>;
isFileTypeSupported(filename: string): boolean;
getSupportedExtensions(): string[];
getFileType(filename: string): string | null;
getGaussianFormat(filename: string): string | null;
}
加载流程:
1. 检查模型容量
2. 检测文件类型 (Gaussian, ONNX, FBX)
3. 路由到适当的加载器(Gaussian 使用 defaultLoader,FBX 使用 FBXLoaderManager)
4. 通过 createGaussianModel() 将加载的数据转换为 ModelEntry
5. 注册到 ModelManager
GaussianLoader
职责:用于创建 GaussianModel 实例的高级便捷服务。
特性:
- 包装 FileLoader 和 ONNXManager 以提供统一 API
- 支持所有高斯格式(PLY, SPZ, KSplat, SPLAT, SOG, Compressed PLY)
- 支持 ONNX 模型
- 自动检测文件格式
- 返回 GaussianModel 实例(Three.js Object3D 包装器)
class GaussianLoader {
createFromGaussian(renderer, modelPath, options?, formatHint?): Promise<GaussianModel>;
createFromPLY(renderer, modelPath, options?): Promise<GaussianModel>;
createFromSPZ(renderer, modelPath, options?): Promise<GaussianModel>;
createFromKSplat(renderer, modelPath, options?): Promise<GaussianModel>;
createFromSplat(renderer, modelPath, options?): Promise<GaussianModel>;
createFromSOG(renderer, modelPath, options?): Promise<GaussianModel>;
createFromONNX(renderer, modelPath, camMat, projMat, options?): Promise<GaussianModel>;
createFromFile(renderer, modelPath, cameraMatrices?, options?, fileType?): Promise<GaussianModel>;
createFromEntry(entry: ModelEntry): GaussianModel;
isFormatSupported(filename: string): boolean;
getSupportedFormats(): string[];
detectFormat(filename: string): string | null;
}
用例: 简化与 Three.js 集成时的模型加载,因为它返回可以直接添加到 Three.js 场景的 GaussianModel 实例。
ONNXManager
职责:管理 ONNX 模型加载和推理。
特性:
- 创建专用的 ONNXGenerator + DynamicPointCloud 对。
- 检测颜色模式/维度(SH vs RGB)。
- 支持静态和动态推理。
- 管理仅 GPU 的管道和资源清理。
class ONNXManager {
loadONNXModel(
device: GPUDevice,
modelPath: string,
cameraMatrix: Float32Array,
projectionMatrix: Float32Array,
name?: string,
options?: ONNXLoadOptions,
): Promise<ModelEntry>;
loadONNXFromFile(
device: GPUDevice,
file: File,
cameraMatrix?: Float32Array | null,
projectionMatrix?: Float32Array | null,
): Promise<ModelEntry>;
updateCameraMatrices(
modelName: string,
cameraMatrix: Float32Array,
projectionMatrix: Float32Array,
): Promise<void>;
disposeModel(modelId: string): void;
dispose(): void;
getGenerator(id: string): ONNXGenerator | undefined;
getPointCloud(id: string): DynamicPointCloud | undefined;
hasONNXModels(): boolean;
getONNXModels(): string[];
getONNXPerformanceStats(): { modelCount: number; totalGenerators: number; totalPointClouds: number };
}
CameraManager
职责:管理相机状态和控制器切换。
亮点: - 初始化相机并在每帧更新。 - 切换轨道/FPS 控制器并处理调整大小事件。 - 基于模型分布计算轨道中心。 - 暴露矩阵、视口、视锥体数据和调试快照。
class CameraManager {
initCamera(canvas: HTMLCanvasElement): void;
resetCamera(): void;
setupCameraForPointCloud(pc: PointCloud): void;
resize(canvas: HTMLCanvasElement): void;
update(dt: number): void;
switchController(type: 'orbit' | 'fps'): void;
getControllerType(): ControllerType;
getController(): IController;
getCamera(): PerspectiveCamera | null;
getCameraMatrix(): mat4;
getProjectionMatrix(): mat4;
getCameraPosition(): vec3 | null;
getCameraRotation(): quat | null;
setCameraPosition(position: vec3): void;
setCameraRotation(rotation: quat): void;
setOrbitCenter(center: vec3): void;
getOrbitCenter(): vec3 | null;
getViewportInfo(): { width: number; height: number; aspect: number } | null;
getFrustumInfo(): { fov: number; near: number; far: number } | null;
isInitialized(): boolean;
getDebugInfo(): any;
}
AnimationManager
职责:更新动态模型(通常由 ONNX 驱动)。
class AnimationManager {
updateDynamicPointClouds(view: mat4, proj: mat4, time: number): void;
controlDynamicAnimation(action: 'start' | 'pause' | 'resume' | 'stop', speed?: number): void;
setDynamicAnimationTime(time: number): void;
getDynamicPerformanceStats(): Array<{ modelName: string; stats: any }>;
}
RenderLoop
职责:协调帧循环和渲染协同。
特性:
- 拥有 requestAnimationFrame 生命周期
- 计算 Delta time 并跟踪 FPS
- 管理渲染状态(背景颜色,高斯缩放)
- 协调每帧更新(相机,动画,渲染)
- 提供性能回调(FPS,点数)
class RenderLoop {
init(gpu: WebGPUContext, renderer: GaussianRenderer, canvas: HTMLCanvasElement): void;
start(): void;
stop(): void;
setGaussianScale(scale: number): void;
getGaussianScale(): number;
setBackgroundColor(color: [number, number, number, number]): void;
getBackgroundColor(): [number, number, number, number];
setCallbacks(callbacks: FPSCallbacks): void;
getState(): AppState;
getPerformanceInfo(): object;
getFPS(): number;
getFrameCount(): number;
getLastFrameTime(): number;
getAverageFrameTime(): number;
isRunning(): boolean;
setTargetFPS(fps: number): void;
getTargetFPS(): number;
getDebugInfo(): object;
}
帧周期:
- 计算 delta time
CameraManager.update(dt)AnimationManager.updateDynamicPointClouds(view, proj, time)- 更新 FPS 计数器
GaussianRenderer.prepareMulti(...)/renderMulti(...)- 调用回调(FPS, 点数)
FBXLoaderManager
职责:加载 FBX 网格文件并将其注册到 ModelManager。
特性: - 包装 Three.js FBXLoader - 提供进度和错误回调 - 与 ModelManager 集成以实现统一的模型跟踪
class FBXLoaderManager {
loadFromFile(file: File, options?): Promise<ModelEntry>;
loadFromUrl(url: string, options?): Promise<ModelEntry>;
dispose(): void;
}
注意: FBX + WebGPU 兼容性有限;为了更好的 WebGPU 支持,推荐使用 GLTF/GLB。
数据流
初始化
1. DOM / 画布验证 (DOMElements)
2. WebGPU 初始化 (`initWebGPU_onnx`)
3. GaussianRenderer 构造
4. CameraManager 初始化
5. RenderLoop 初始化 + 启动
事件/数据流
示例链: - 文件拖放 →onFileLoad → FileLoader.loadFile → ModelManager.addModel → RenderLoop 获取新模型。
- ONNX 加载 → ONNXManager.loadONNXModel → DynamicPointCloud 输出 → 预处理 → 排序 → 渲染。
- 控制器切换 → CameraManager.switchController → UI 更新活动控制方案。
Manager 通信
依赖注入
class App {
constructor() {
this.modelManager = new ModelManager(MAX_MODELS);
this.cameraManager = new CameraManager();
this.animationManager = new AnimationManager(this.modelManager);
this.renderLoop = new RenderLoop(this.modelManager, this.animationManager, this.cameraManager);
this.fileLoader = new FileLoader(this.modelManager, loadingCallbacks);
this.onnxManager = new ONNXManager(this.modelManager);
}
}
回调契约
interface LoadingCallbacks {
onProgress: (show: boolean, text?: string, pct?: number) => void;
onError: (msg: string) => void;
}
interface UICallbacks {
onFileLoad(file: File): Promise<void>;
onSampleLoad(filename: string): void;
onResetCamera(): void;
onGaussianScaleChange(scale: number): void;
onBackgroundColorChange(color: [number, number, number, number]): void;
onControllerSwitch(type: 'orbit' | 'fps'): void;
}
优势
- 模块化 – 清晰的关注点分离。
- 可扩展性 – 可以通过引入新的 Manager 来添加新功能。
- 可测试性 – Manager 可以通过模拟依赖项独立测试。
- 性能 – 职责可以隔离优化,减少竞争。
Manager 通信模式
依赖注入
Manager 通过构造函数接收依赖:
- FileLoader 需要 ModelManager 和 LoadingCallbacks
- AnimationManager 需要 ModelManager
- RenderLoop 需要 ModelManager、AnimationManager 和 CameraManager
- GaussianLoader 需要 FileLoader 和 ONNXManager
回调契约
Manager 使用回调处理横切关注点:
LoadingCallbacks:
interface LoadingCallbacks {
onProgress?: (show: boolean, text?: string, pct?: number) => void;
onError?: (message: string) => void;
}
FPSCallbacks:
interface FPSCallbacks {
onFPSUpdate?: (fps: number) => void;
onPointCountUpdate?: (count: number) => void;
}
数据流
- 加载:
FileLoader→ModelManager.addModel()→RenderLoop获取新模型 - 动态更新:
ONNXManager→DynamicPointCloud→AnimationManager.update()→RenderLoop - 相机:
CameraManager→RenderLoop使用相机矩阵进行渲染