跳转至

Uniform模块 API 参考

本文档涵盖了 src/uniform/ 的导出内容:UniformBuffer 实现、支持接口以及 UniformUtils 辅助类。

类型与接口 (Types & interfaces)

UniformData

type UniformData = ArrayBufferView | ArrayBuffer;

任何类型化数组(例如 Float32Array, Uint32Array, DataView)或原始 ArrayBuffer 都可以传递给 UniformBuffer 构造函数。

IUniformBuffer

interface IUniformBuffer {
  readonly buffer: GPUBuffer;
  readonly bindGroup: GPUBindGroup;
  readonly size: number;
  readonly label?: string;
  readonly data: ArrayBuffer;
  setData(view: ArrayBufferView): void;
  flush(device?: GPUDevice): void;
  clone(device?: GPUDevice): IUniformBuffer;
  destroy(): void;
}

UniformBuffer 实现了此接口。

UniformConfig

interface UniformConfig {
  device: GPUDevice;
  data: UniformData;
  label?: string;
  usage?: GPUBufferUsageFlags; // 可选的额外 usage 位
}

当前的实现接受 (device, data, label?),但导出此配置接口是为了未来的池化/用法覆盖。

类: UniformBuffer

class UniformBuffer implements IUniformBuffer {
  constructor(device: GPUDevice, init: UniformData, label?: string);

  static bindGroupLayout(device: GPUDevice): GPUBindGroupLayout;

  readonly buffer: GPUBuffer;
  readonly bindGroup: GPUBindGroup;
  readonly label?: string;
  readonly size: number;
  get data(): ArrayBuffer;
  set dataBytes(bytes: ArrayBuffer);
  setData(view: ArrayBufferView): void;
  flush(device?: GPUDevice): void;
  clone(device?: GPUDevice): UniformBuffer;
  destroy(): void;
}

构造函数

  • 将初始数据复制到内部 ArrayBuffer 缓存中。
  • 分配一个具有 GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST 用途的 GPU 缓冲。
  • 将初始字节写入 GPU,并使用共享布局创建绑定组。

static bindGroupLayout(device)

返回(并允许 WebGPU 缓存)规范的统一绑定组布局:

entry: {
  binding: 0,
  visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,
  buffer: { type: 'uniform' },
}

setData(view)

将类型化数组复制到 CPU 缓存中。如果 view.byteLength !== size 则抛出异常。

flush(device?)

通过 queue.writeBuffer 将缓存的字节上传到 GPU。如果未提供 device,则使用构造时存储的 device。

data / dataBytes

  • data 返回缓存的克隆 ArrayBuffer(用于调试或序列化)。
  • dataBytes = newBytes 完全替换缓存(大小必须匹配)。

clone(device?)

构造一个新的具有相同字节的 UniformBuffer(在复制每个相机的 Uniform 时很有用)。

destroy()

调用 buffer.destroy();不会将绑定组置空(调用者管理引用)。

类: UniformUtils

class UniformUtils {
  static alignSize(size: number): number;
  static createAlignedBuffer(size: number): ArrayBuffer;
  static packFloat32Array(values: number[], targetSize?: number): Float32Array;
  static packVec(values: number[], vecSize: 2 | 3 | 4): Float32Array;
  static packMat4(matrix: Float32Array | number[]): Float32Array;
}
  • alignSize – 向上取整到下一个 16 字节的倍数。
  • createAlignedBuffer – 返回一个已对齐的 ArrayBuffer(零填充)。
  • packFloat32Array – 将数字数组写入给定长度的 Float32Array(如果需要,用零填充)。
  • packVec – 处理 vec2/vec3/vec4 填充(vec3 提升为 vec4)。
  • packMat4 – 确确保输入有 16 个元素并返回列主序的 Float32Array(传递现有的 Float32Array 以避免复制)。

使用片段

创建并绑定 Uniform

import { UniformBuffer } from 'src/uniform';

const projBytes = new Float32Array(16); // 64 bytes
const projUniform = new UniformBuffer(device, projBytes, 'projection');

renderPass.setBindGroup(0, projUniform.bindGroup);

每帧更新

function updateCamera(cameraBytes: Float32Array) {
  cameraUniform.setData(cameraBytes);
  cameraUniform.flush();
}

打包结构体

const settingsData = new Float32Array(20); // 80 bytes
// 填充裁剪框、缩放等
settingsUniform.setData(settingsData);
settingsUniform.flush();

为多个相机克隆

const mainCam = new UniformBuffer(device, mainData, 'main-camera');
const debugCam = mainCam.clone();

注意事项

  • 每个 UniformBuffer 保留自己的 CPU 缓存。如果需要在缓冲之间共享字节,写入一次缓存 (setData) 并调用 clone()
  • 所有辅助函数都假设 WebGPU 的 16 字节对齐。手动构造结构体时,首选 UniformUtils.createAlignedBuffer 以避免差一错误 (off-by-one mistakes)。
  • 该模块不会自动 flush;调用者决定何时进行 GPU 上传,以便在编码 Pass 之前批量更新。