跳转至

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            │
└─────────────────────────────────────────────────────────────┘

架构原则

  1. 单一职责 (Single Responsibility) – 每个文件只解决一类问题(例如,half.ts 负责所有 float16 相关事务)。
  2. 分配感知 (Allocation Awareness) – 热路径重用类型化数组和暂存缓冲以保持对 GC 友好。
  3. 不可变输入 (Immutable Inputs) – 数学辅助函数(Aabb, planeFromPoints, 相机数学)克隆或返回新值,以避免上游状态泄漏。
  4. 快速失败的可调试性 (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 个半精度值(24 u32),因此 WGSL 结构体无论使用哪个 SH 阶数都可以假设恒定的步幅。
  • shNumCoefficients / shDegreeFromNumCoeffs 允许管理器在尝试分配 GPU 缓冲之前验证有效载荷元数据。

数据流:

PLY/ONNX 行 → float32 数学 (sigmoid/exp/cov) → packF16Array/makeCopySH → Uint32Array 缓冲 → 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),和渲染器更新。这种分解保持逻辑可组合——如果调用者只需要环境克隆,可以跳过某些步骤。

渲染器资源规则:

配置 (色调映射, 清除颜色) → 通过复制共享
GPU 资源 (PMREM 纹理, 缓冲) → 每个渲染器重新创建
效果/Pass                  → 由调用者重新创建

关键数据流

环境引导 (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/Uint32ArraymakeCopySH_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 代码。