Utils模块架构
Utils模块 是 Visionary 的共享基础。它不是一个单一用途的数学库,而是分为四个协作的子系统,为渲染器、管理器和 IO 管道提供数据:
┌─────────────────────────────────────────────────────────────┐
│ 应用层 (Application Layer) │
│ (Renderers · Managers · IO · Controllers · Diagnostics) │
├─────────────────────────────────────────────────────────────┤
│ Utils模块 │
│ ┌────────────┬──────────────┬──────────────┬─────────────┐ │
│ │ 核心数学 │ 数据布局 │ GPU 运行时 │ 渲染器操作 │ │
│ │ (vec/aabb) │ (float16/SH) │ (read/profil)│ (env/init) │ │
│ └────────────┴──────────────┴──────────────┴─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ gl-matrix · WebGPU · three/webgpu │
└─────────────────────────────────────────────────────────────┘
架构原则
- 单一职责 (Single Responsibility) – 每个文件只解决一类问题(例如,
half.ts负责所有 float16 相关事务)。 - 分配感知 (Allocation Awareness) – 热路径重用类型化数组和暂存缓冲以保持对 GC 友好。
- 不可变输入 (Immutable Inputs) – 数学辅助函数(
Aabb,planeFromPoints, 相机数学)克隆或返回新值,以避免上游状态泄漏。 - 快速失败的可调试性 (Fail-Fast Debuggability) – 渲染器和 GPU 辅助函数执行防御性检查(设备可用性、缓冲使用标志、时间戳特性检测),并提供显式日志以缩短反馈循环。
子系统
1. 核心数学 (Math Core)
组件: aabb.ts, camera-math.ts, transforms.ts, vector-math.ts
Aabb封装最小/最大边界并提供只读的center()/radius()辅助函数。内部使用vec3.clone克隆向量以保证不可变性。- 相机数学函数实现针孔相机模型 (
fov = 2 * atan(pixels / (2 * focal))) 并位于其自己的模块中,因此可以将它们摇树优化 (tree-shaken) 到 IO 和运行时控制器中。 VIEWPORT_Y_FLIP一次性预计算,以防止在渲染循环中重复调用mat4.fromValues。vector-math暴露简单的基于元组的操作和planeFromPoints。平面拟合器依赖于协方差构建 + 幂迭代特征向量查找器;它可以选择强制向上法线以匹配 UI 预期。
设计目标:
- 零共享状态,
- 始终数值安全(仅当向量无法归一化时才返回 NaN 三元组),并且
- 如果繁重的预处理移出主线程,易于移植到 Worker。
2. 数据布局与 Float16 (Data Layout & Float16)
组件: half.ts, gpu.ts 中的相关导出
f32_to_f16/f16_to_f32包装了一个符合 IEEE‑754 标准的转换管线。诸如可配置的舍入、FTZ、溢出饱和、规范 NaN 和遗留指数截止等功能,使我们在验证回归时能够模拟历史数据集。packF16Array/unpackF16Array是在加载 ONNX 权重或流式传输高斯参数时使用的批量辅助函数。makeCopySH_PackedF16将通道优先的源属性(f_dc_*,f_rest_*)重新打包为着色器友好的[R0,G0,B0, R1,G1,B1, ...]顺序。它总是写入 48 个半精度值(24u32),因此 WGSL 结构体无论使用哪个 SH 阶数都可以假设恒定的步幅。shNumCoefficients/shDegreeFromNumCoeffs允许管理器在尝试分配 GPU 缓冲之前验证有效载荷元数据。
数据流:
转换子系统是有意无状态的;IO Module 协调它,但 Utils 保证所有导入器的数学和布局一致。
3. GPU 运行时与仪表化 (GPU Runtime & Instrumentation)
组件: gpu.ts, debug-gpu-buffers.ts
align4/align8应用按位取整以满足 WebGPU 复制和映射约束。它们被readWholeBuffer以及 ONNX 上传辅助函数重用。readWholeBuffer执行端到端回读:创建暂存缓冲 → 复制 → 等待 → 映射 → 切片请求的字节 → 销毁暂存缓冲。可选的queue.onSubmittedWorkDone()调用受到保护,因此它可以在缺少该 API 的浏览器上运行。GPUStopwatch包装时间戳查询集。它强制每次测量一个标签,防止容量溢出,并在映射之前将查询解析到其自己的缓冲。所有计时均以纳秒为单位返回。- 高斯数学辅助函数(
buildCov,sigmoid)位于此处,因为它们紧接在 GPU 上传之前运行。 debug-gpu-buffers.ts增加了更高级别的诊断:读取 ONNX 计数缓冲,比较跨缓冲的值,以及跟踪整个计数管线。这些辅助函数在生产构建中调用是安全的,因为它们在 GPU 队列中设置屏障并在使用后销毁临时缓冲。createShaderDebugBuffer/readShaderDebugBuffer为着色器作者提供了一条认可的途径,将中间计算结果转储回 JS 进行检查。
4. 渲染器与环境操作 (Renderer & Environment Operations)
组件: env-map-helper.ts, renderer-init-helper.ts
EnvMapHelper管理与 HDR 环境相关的一切:通过RGBELoader加载.hdr文件,使用兼容 WebGPU 的PMREMGenerator生成 PMREM,将色调映射/曝光与现有渲染器同步,并在可用时使用 WebGPU 的updateEnvironment钩子更新场景。每一步都验证渲染器后端/设备可用性,因为构建产物可能会异步水合 Three.js 内部结构。RendererInitHelper是协调器,它克隆渲染器状态,同时确确保 GPU 资源不共享。它暴露:RendererInitOptions用于传递源渲染器、原始 HDR 纹理、所需尺寸和回退 HDR URL。initializeRenderer它 (1) 从源渲染器复制配置或应用默认值,(2) 强制执行尺寸/像素比,(3) 决定是重用现有环境还是加载回退 HDR,(4) 为每个渲染器创建一个新的 PMREM 纹理,以及 (5) 更新渲染器 + 场景引用。isRendererInitialized用于在执行昂贵操作(例如,截图捕获)之前的守卫子句。- 内部辅助函数分离职责:配置复制(
setupClearColor, 色调映射, 颜色空间, 光照标志),环境溯源(setupEnvironmentFromSource,setupDefaultEnvironment),和渲染器更新。这种分解保持逻辑可组合——如果调用者只需要环境克隆,可以跳过某些步骤。
渲染器资源规则:
关键数据流
环境引导 (Environment Bootstrap)
sourceRenderer? ──► setupRendererConfig ──► renderer
│
└─ 有 scene.environment?
│ 是 否
▼ ▼
setupEnvironmentFromSource setupDefaultEnvironment
│ │
originalTexture? ──► createEnvironmentMap ◄─ 回退 HDR
│
▼
scene.environment / background 更新
ONNX 计数调试管线
ONNX 输出缓冲 ──► readONNXCountBuffer (u32)
│
▼
模型参数缓冲 ──► readModelParamsNumPoints (u32)
│
▼
着色器存储 ──► compareBufferValues / readShaderDebugBuffer
此管线提供了不匹配首次发生位置的即时可见性,允许工程师区分 ONNX 推理失败和 GPU 复制时序问题。
内存与可靠性策略
- 视图重用 –
half.ts为所有转换维护一对Float32Array/Uint32Array;makeCopySH_PackedF16每个点打包到一个临时的Uint16Array(48),以保持代码简单且可预测。 - 显式清理 – 每个暂存缓冲 (
readWholeBuffer, 调试辅助函数) 都会被显式取消映射/销毁;PMREM 生成器在生成环境纹理后立即被处置。 - 输入验证 – 如果后端或设备缺失,渲染器辅助函数会提前退出,如果缓冲未定义,GPU 调试辅助函数会拒绝启动。
- 确定性布局 – SH 打包填充到恒定步幅,float16 打包暴露
wordsPerPoint元数据,因此下游 GPU 结构体永远不需要猜测。
集成点
- Managers & Controllers: 调用渲染器辅助函数为缩略图克隆视图,重用数学工具进行相机约束,并依赖
GPUStopwatch进行每阶段计时叠加。 - IO Module: 拥有文件解析权,但将所有的 float16/SH 转换委托给 Utils,以确保 ONNX, KSplat, 和 PLY 源产生完全相同的 GPU 载荷。
- Renderer: 在 Three.js/WebGPU 管线内消费
Aabb, 协方差数学, 和变换常量。 - Diagnostics & QA: 在现场测试期间运行
debugCountPipeline和着色器调试缓冲,无需构建自定义脚本。
通过隔离这些职责同时保持 API 微小,即使 Visionary 演进,Utils模块仍保持稳定——新格式或渲染器模式可以重用相同的原语,而无需复制脆弱的数学或 GPU 代码。