Preprocessing 模块
Preprocessing 模块将 GPU 驻留的 3D 高斯 Splat 转换为排序器和渲染器可以消费的屏幕空间 Splat。它封装了 WebGPU 计算管道 (preprocess.wgsl),打包相机 + 渲染 Uniform,评估每个高斯的球谐函数(或原始 RGB),并将结果写入一帧中所有模型共享的全局 2D Splat 缓冲区。
职责
- 感知相机的投影 – 打包视图/投影矩阵(带 WebGPU Y 翻转),计算焦距,并每帧将其流式传输到着色器。
- 点云绑定 – 复用
PointCloud拥有的缓冲区(gaussians,sh, 绘制 Uniform, 模型参数)并将它们连接到计算绑定组中。 - 3D→2D 转换 – 投影位置,通过剔除框进行裁剪,将 3×3 协方差转换为屏幕空间椭圆,并可选择执行 mip-splatting 不透明度调制。
- 颜色评估 – 执行高达 3 阶的 SH 评估,或者当
useRawColor=true时,将 SH 缓冲区视为直接 RGBA 以匹配DynamicPointCloud输出。 - 排序器握手 – 将打包的 Splat 发送到全局
splat2D缓冲区,填充深度键/负载,并更新GPURSSorter所需的原子计数器(keys_size,间接dispatch_x)。 - 多模型分发 – 暴露
dispatchModel(...),以便渲染器可以在运行单个全局基数排序之前,将多个点云流式传输到同一输出缓冲区的连续切片中。
核心组件
GaussianPreprocessor(src/preprocess/gaussian_preprocessor.ts) – 拥有计算管道、Uniform 缓冲区和dispatchModel的具体实现。preprocess.wgsl(src/shaders/preprocess.wgsl) – 每个工作组 256 个线程执行的着色器入口点;每个线程展开一个高斯。preprocess/index.ts– 定义PreprocessArgs、IPreprocessor,并重新导出具体类供渲染器和工具使用。SortedSplats/GPURSSorter– 暴露sorter_bg_pre、sorter_uni和sorter_dis的排序资源;预处理更新这些资源,以便基数排序可以直接运行或通过间接分发运行。
数据流
[PointCloud GPU 缓冲区] ─┐
├─► GaussianPreprocessor.dispatchModel
[相机 + 渲染设置] ───────┘ │
▼
全局 2D Splat 缓冲区 + 排序缓冲区
│
▼
GPURSSorter (基数排序) ─► Renderer
渲染器通常实例化两个预处理器(SH + 原始 RGB),每个点云调用一次 dispatchModel,然后运行单个基数排序,随后进行间接绘制。
Uniform & 缓冲区快照
| 资源 | 大小 | 生产者 | 备注 |
|---|---|---|---|
| 相机 Uniform | 272 B | GaussianPreprocessor.packCameraUniforms |
视图, 视图⁻¹, 投影 (Y翻转), 投影⁻¹, 视口, 焦距。 |
| 渲染设置 | 80 B | packSettingsUniforms |
剔除框, 高斯缩放, 最大 SH 阶数, 环境/Mip 标志, 内核大小, walltime, 场景范围, 中心。 |
| 模型参数 | 128 B | PointCloud.updateModelParamsWithOffset |
模型矩阵, 基偏移, numPoints, 着色旋钮, 精度元数据;每次分发刷新。 |
全局 splat2D |
numPoints × 32 B |
Renderer | 共享输出缓冲区;dispatchModel 写入 [baseOffset, baseOffset + count) 切片。 |
排序缓冲区 (sorter_bg_pre) |
可变 | GPURSSorter |
保存键/值乒乓缓冲区,间接分发,以及预处理通过原子更新的原子计数器。 |
计算阶段 (每个高斯)
- 加载与解包 打包的 f16 位置、不透明度、协方差和 SH/RAW 系数。
- 转换 位置到相机空间;预先应用剔除框和视锥体检查以尽早丢弃不可见的 Splat。
- 投影协方差 通过将 3×3 对称矩阵与透视投影的解析雅可比矩阵相乘 (
Σ₂D = Jᵀ · W · Σ₃D · Wᵀ · J)。 - 特征分解 2×2 协方差以推导椭圆轴;添加
kernelSize用于抗锯齿和可选的 mip-splatting 不透明度调整。 - 评估颜色 通过 SH 多项式(阶数受
settings.maxSHDegree限制)或,如果USE_RAW_COLOR=1,将 SH 缓冲区重新解释为打包的 RGBA。 - 写入输出 到全局
splat2D缓冲区(打包的 f16 轴、位置、颜色)并为排序器发出匹配的深度键 / 负载索引。 - 更新计数器 使用原子操作 (
keys_size,dispatch_x),以便基数排序器可以运行固定分发或消费预处理期间产生的间接计数。
多模型分发
GaussianPreprocessor.dispatchModel 接受:
camera,viewport–PerspectiveCamera加上[width, height]。pointCloud– 提供高斯/SH 缓冲区、绘制 Uniform 和每个模型的 Uniform 缓冲区。sortStuff– 包含sorter_bg_pre、sorter_uni和sorter_dis的全局PointCloudSortStuff。settings– 渲染器生成的结构体(缩放、SH 阶数、剔除框等)。modelMatrix&baseOffset– 传递给PointCloud.updateModelParamsWithOffset,以便每个模型写入全局 Splat 缓冲区的唯一切片。global.splat2D– 帧中每个模型共享的输出存储。countBuffer?– 可选的 ONNX 生成的 GPU 缓冲区;在 Uniform 刷新后,其值覆盖modelParams.num_points(字节偏移量 68),启用间接绘制以跟踪动态点数。
该方法在可用时还会调用 pointCloud.setPrecisionForShader(),以便量化缓冲区在分发之前将其缩放/零点发布到 Uniform 块中。
使用示例
// 初始化 (渲染器启动)
const preprocessorSH = new GaussianPreprocessor();
await preprocessorSH.initialize(device, /*shDegree*/ 3, /*useRawColor*/ false);
const preprocessorRGB = new GaussianPreprocessor();
await preprocessorRGB.initialize(device, 0, true);
// 每帧:将每个点云预处理到全局缓冲区
const encoder = device.createCommandEncoder();
let baseOffset = 0;
for (const pc of pointClouds) {
const pre = pc.colorMode === 'rgb' ? preprocessorRGB : preprocessorSH;
const countBuffer = 'countBuffer' in pc ? pc.countBuffer?.() : undefined;
pre.dispatchModel({
camera,
viewport: [width, height],
pointCloud: pc,
sortStuff: globalSortStuff,
settings: buildRenderSettings(pc, frameSettings),
modelMatrix: pc.transform,
baseOffset,
global: { splat2D: globalSplatBuffer },
countBuffer,
}, encoder);
baseOffset += pc.numPoints;
}
// 稍后在帧中:运行全局基数排序 + 渲染器绘制
性能与调优
- 工作组大小 256 在桌面和移动 GPU 上保持高占用率。
- 提前退出 (视锥体 + 剔除框) 避免对剔除的 Splat 进行不必要的矩阵运算。
- 打包的 f16 缓冲区 将高斯属性和 SH 数据的带宽减半。
- 原子争用 随着极高的可见率而增加;考虑在密集场景中进行激进的剔除框或更小的
gaussianScaling。 - 双管道 (SH 与原始 RGB) 避免运行时分支;
USE_RAW_COLOR通过管道常量编译到着色器中。
集成点
- Point Cloud (点云) 模块 – 提供 GPU 缓冲区和模型参数 Uniform;为量化 ONNX 输出暴露
setPrecisionForShader。 - Sorting (排序) 模块 – 提供带有预处理绑定组的
PointCloudSortStuff;从计算通道接收更新的计数器和深度键。 - Renderer (渲染器) 模块 – 拥有全局
splat2D缓冲区,编排多模型分发,并触发单个全局基数排序,随后进行间接绘制。 - Camera (相机) 系统 –
PerspectiveCamera提供矩阵和焦距数据;该模块在内部处理求逆和 Y 翻转打包。