Uniform模块 API 参考
本文档涵盖了 src/uniform/ 的导出内容:UniformBuffer 实现、支持接口以及 UniformUtils 辅助类。
类型与接口 (Types & interfaces)
UniformData
任何类型化数组(例如 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 之前批量更新。