跳转至

Renderer API 参考

本文档涵盖了 src/renderer/ 的公开接口。它跟踪实际的 TypeScript 导出,以便集成者可以配置、驱动和检查 GaussianRenderer

导出项 (Exports)

import {
  GaussianRenderer,
  DEFAULT_KERNEL_SIZE,
  type RendererConfig,
  type RenderArgs,
  type RenderStats,
  type IRenderer,
} from 'src/renderer';

接口 (Interfaces)

RenderArgs

interface RenderArgs {
  camera: PerspectiveCamera;        // 必须提供的视图/投影提供者
  viewport: [number, number];       // 画布宽度/高度(像素)
  clippingBox?: { min: vec3; max: vec3 };
  maxSHDegree?: number;
  showEnvMap?: boolean;
  mipSplatting?: boolean;
  kernelSize?: number;
  walltime?: number;
  sceneExtend?: number;
  sceneCenter?: vec3;
}

在每次调用 dispatchModel 之前,这些值会在 buildRenderSettings() 内部与每个点云的元数据合并。任何省略的字段都将回退到 PointCloud 的默认值(bbox、中心点、PointCloud.kernelSize 等)。

RendererConfig

interface RendererConfig {
  device: GPUDevice;
  format: GPUTextureFormat;  // 交换链 / 渲染目标格式
  shDegree: number;          // 此渲染器支持的最大 SH 阶数
  compressed?: boolean;      // 为未来的压缩数据路径保留
  debug?: boolean;           // 启用详细日志记录和全局句柄
}

旧版的构造函数 (device, format, shDeg, compressed?) 仍然受支持,但推荐使用配置对象。

RenderStats

interface RenderStats {
  gaussianCount: number;   // pointCloud.numPoints
  visibleSplats: number;   // 最新的排序器 keys_size / 缓存的 num_points
  memoryUsage: number;     // 粗略估计值(splat + 排序器缓冲)
}

IRenderer

interface IRenderer {
  initialize(): Promise<void>;
  prepareMulti(
    encoder: GPUCommandEncoder,
    queue: GPUQueue,
    pointClouds: PointCloud[],
    args: RenderArgs,
  ): void;
  render(pass: GPURenderPassEncoder, pointCloud: PointCloud): void;
  renderMulti(pass: GPURenderPassEncoder, pointClouds: PointCloud[]): void;
  getPipelineInfo(): { format: GPUTextureFormat; bindGroupLayouts: GPUBindGroupLayout[] };
}

GaussianRenderer 实现了此接口,并添加了一些如下所述的便捷/调试辅助方法。

GaussianRenderer

构造函数

new GaussianRenderer({ device, format, shDegree, compressed?, debug? }: RendererConfig)
new GaussianRenderer(device: GPUDevice, format: GPUTextureFormat, shDegree: number, compressed?: boolean)

两种形式是等价的;配置对象版本支持未来的选项而不破坏调用点。

生命周期

  • initialize(): Promise<void> – 创建排序器、双预处理器、管线布局、渲染/深度管线、间接绘制缓冲以及初始的 100 万 Splat 全局缓冲。
  • ensureSorter(): Promise<void> – 旧版别名,如果需要,仅调用 initialize()

帧入口点

  • prepareMulti(encoder, queue, pointClouds, args)
  • 确保全局容量 – pointCloud.numPoints 的总和(1.25 倍增长因子)。
  • 重置排序器的间接缓冲和 keys_size
  • 对于每个点云:选择 SH 或 RGB 预处理器,使用 baseOffset + 可选的 ONNX countBuffer 调用 dispatchModel
  • 运行单次 sorter.recordSortIndirect(...) 并将可见 Splat 计数复制到间接绘制缓冲中。
  • render(pass, pointCloud)
  • 使用每个云缓存的排序资源 (WeakMap)。
  • @group(0) 绑定 pointCloud.renderBindGroup(),在 @group(1) 绑定缓存的排序器渲染绑定组。
  • 使用共享的间接缓冲发出一次 drawIndirect
  • renderMulti(pass, pointClouds)
  • 要求事先调用 prepareMulti
  • 绑定全局 renderBG(全局 splat 缓冲)和全局排序器渲染绑定组,然后调用一次 drawIndirect

管线控制

  • getPipelineInfo() – 返回 { format, bindGroupLayouts: [PointCloud.renderBindGroupLayout(device), GPURSSorter.createRenderBindGroupLayout(device)] } 供外部渲染通道使用。
  • setDepthEnabled(enabled: boolean) – 切换后续绘制中是否使用深度感知管线变体。
  • setDepthFormat(format: GPUTextureFormat) – 默认更新 depth24plus;重新创建深度管线以匹配新的附件格式。

诊断与统计

  • getRenderStats(pointCloud) – 包装 RenderStats 用于 UI 叠加层或日志记录。
  • readInstanceCountDebug() – GPU→CPU 回读当前的间接实例计数。
  • readPayloadSampleDebug(n = 8) – 从全局排序器缓冲转储前 n 个负载索引(需要 prepareMulti / 全局缓冲)。
  • debugONNXCount() – 当 ONNX 驱动的计数处于活动状态时,挂钩到预处理器的调试例程。

实用工具

  • DEFAULT_KERNEL_SIZE – 导出的常量 (0.3),当未提供 RenderArgs.kernelSizePointCloud.kernelSize 时使用。

使用模式

多模型帧

const renderer = new GaussianRenderer({ device, format, shDegree: 3 });
await renderer.initialize();

renderer.prepareMulti(encoder, device.queue, pointClouds, {
  camera,
  viewport: [canvas.width, canvas.height],
  maxSHDegree: 3,
});

const pass = encoder.beginRenderPass(passDesc);
renderer.renderMulti(pass, pointClouds);
pass.end();

单模型渲染(旧路径)

旧路径指的是在引入多模型批处理(prepareMulti/renderMulti)之前使用的逐模型渲染方式。虽然现在仍然支持,但推荐使用批处理方式,即使是单个模型。

旧路径特点: - 使用 render(pass, pointCloud) 方法,每个模型单独调用 - 使用每个点云自己的 splat2DBuffer(由 PointCloud 模块管理) - 使用缓存的每云排序资源(WeakMap<PointCloud, PointCloudSortStuff>) - 每个模型单独执行绘制调用

const pointCloud = loadPointCloud();
renderer.prepareMulti(encoder, device.queue, [pointCloud], args); // 仍然推荐
renderer.render(pass, pointCloud); // 使用每云缓存,单独绘制

注意:即使是单个模型,也推荐使用 renderMulti(),因为它使用全局缓冲区,性能更好。

深度管线切换

renderer.setDepthFormat('depth32float');
renderer.setDepthEnabled(true);

调试辅助

await renderer.readInstanceCountDebug();
await renderer.readPayloadSampleDebug(16);
await renderer.debugONNXCount();

注意事项

  • 务必在 renderMulti 之前调用 prepareMulti;预处理会填充排序器缓冲和间接绘制计数。
  • 如果仅渲染单个点云,缓存仍然有效,但容量管理可能会跳过全局缓冲,直到使用了 prepareMulti
  • 统计和调试实用程序会回读 GPU 缓冲;在生产版本中应谨慎使用。