typegpu
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTypeGPU
TypeGPU
A single schema () defines a GPU type, CPU buffer layout, and TypeScript type at once - no manual alignment, type mapping, or casting. The build plugin transforms -marked TypeScript for runtime WGSL transpilation, enabling type inference and polymorphism across the CPU/GPU boundary.
d.*unplugin-typegpu'use gpu'This skill targets TypeGPU . If the user's project is on an older release, verify API availability before relying on examples or recommended patterns here.
0.11.2一套架构()可同时定义 GPU 类型、CPU 缓冲区布局和 TypeScript 类型——无需手动对齐、类型映射或强制转换。构建插件 会转换标记有 的 TypeScript 代码,实现运行时 WGSL 转译,支持 CPU/GPU 边界间的类型推断与多态性。
d.*unplugin-typegpu'use gpu'本技能针对 TypeGPU 版本。如果用户项目使用旧版本,在参考示例或推荐模式前,请先验证 API 是否可用。
0.11.2When to read reference files
何时查阅参考文档
Read before writing virtually any shader or GPU function — these two cover the rules that trip people up most:
- — abstract type resolution, exactly when
references/types.mdis required vs redundant, sampler/texture schemas ford.f32()signatures, CPU-sidetgpu.fn/TgpuBufferTypeScript types. If you skip this, you'll hit type errors.TgpuTexture - — full
references/shaders.mdlibrary listing, loops (std,std.range),tgpu.unroll, outer-scope capture rules, complete builtin reference for all three shader stages,tgpu.comptime. Read this for any non-trivial shader logic.console.log
Read when the task specifically involves:
- — vertex buffers/layouts,
references/pipelines.mdwiring, MRT, fullscreen triangle, depth/stencil, blend modes,attribsoutput, loading 3D models (fragDepth), resolve API@loaders.gl - —
references/matrices.mdintegration, column-major layout, camera uniforms,wgpu-matrix, fast-path CPU writes. Read for any 3D work (view/projection matrices, animated transforms, model loading)common.writeSoA - — texture creation, views, samplers, storage textures, mipmaps, multisampling
references/textures.md - —
references/noise.md(random, distributions, Perlin 2D/3D)@typegpu/noise - —
references/sdf.md(2D/3D primitives, operators, ray marching, AA masking)@typegpu/sdf - — install,
references/setup.mdbuild plugin,unplugin-typegpuoperator overloadingtsover - — buffer reinterpretation, indirect drawing/dispatch, custom encoders
references/advanced.md
在编写几乎所有着色器或 GPU 函数前阅读——这两份文档涵盖了最容易出错的规则:
- —— 抽象类型解析、
references/types.md的必要与冗余场景、d.f32()签名的采样器/纹理架构、CPU 端tgpu.fn/TgpuBufferTypeScript 类型。如果跳过此文档,你会遇到类型错误。TgpuTexture - —— 完整的
references/shaders.md库列表、循环(std、std.range)、tgpu.unroll、外部作用域捕获规则、所有三个着色器阶段的完整内置函数参考、tgpu.comptime。编写任何非 trivial 的着色器逻辑时请阅读此文档。console.log
当任务具体涉及以下内容时阅读:
- —— 顶点缓冲区/布局、
references/pipelines.md连接、MRT(多渲染目标)、全屏三角形、深度/模板、混合模式、attribs输出、加载 3D 模型(fragDepth)、解析 API@loaders.gl - ——
references/matrices.md集成、列主序布局、相机 uniforms、wgpu-matrix、CPU 快速写入路径。任何 3D 工作(视图/投影矩阵、动画变换、模型加载)都需阅读此文档common.writeSoA - —— 纹理创建、视图、采样器、存储纹理、Mipmap、多重采样
references/textures.md - ——
references/noise.md(随机数、分布、2D/3D Perlin 噪声)@typegpu/noise - ——
references/sdf.md(2D/3D 基本体、运算符、光线步进、抗锯齿遮罩)@typegpu/sdf - —— 安装、
references/setup.md构建插件、unplugin-typegpu运算符重载tsover - —— 缓冲区重解释、间接绘制/调度、自定义编码器
references/advanced.md
Setup
初始化
ts
import tgpu, { d, std, common } from 'typegpu';
const root = await tgpu.init(); // request a GPU device
const root = tgpu.initFromDevice(device); // or wrap an existing GPUDevice
const context = root.configureContext({ canvas, alphaMode: 'premultiplied' });Create one root at app startup. Resources from different roots cannot interact.
ts
import tgpu, { d, std, common } from 'typegpu';
const root = await tgpu.init(); // 请求 GPU 设备
const root = tgpu.initFromDevice(device); // 或包装现有 GPUDevice
const context = root.configureContext({ canvas, alphaMode: 'premultiplied' });在应用启动时创建一个 root。不同 root 的资源无法交互。
Data schemas (d.*
)
d.*数据架构(d.*
)
d.*A schema defines memory layout and infers TypeScript types; the same schema is used for buffers, shader signatures, and bind group entries.
架构定义内存布局并推断 TypeScript 类型;同一架构可用于缓冲区、着色器签名和绑定组条目。
Scalars
标量
ts
d.f32 d.i32 d.u32 d.f16
// d.bool is NOT host-shareable - use d.u32 in buffersts
d.f32 d.i32 d.u32 d.f16
// d.bool 不可与主机共享——在缓冲区中使用 d.u32Vectors and matrices
向量与矩阵
ts
d.vec2f d.vec3f d.vec4f // f32
d.vec2i d.vec3i d.vec4i // i32
d.vec2u d.vec3u d.vec4u // u32
d.vec2h d.vec3h d.vec4h // f16
d.mat2x2f d.mat3x3f d.mat4x4fInstance types: -> , -> .
d.vec3f()d.v3fd.mat4x4f()d.m4x4fVector constructors are richly overloaded - use them. They compose from any mix of scalars and smaller vectors that adds up to the right component count:
ts
d.vec3f() // zero-init: (0, 0, 0)
d.vec3f(1) // broadcast: (1, 1, 1)
d.vec3f(1, 2, 3) // individual components
d.vec3f(someVec2, 1) // vec2 + scalar
d.vec3f(1, someVec2) // scalar + vec2
d.vec4f() // zero-init: (0, 0, 0, 0)
d.vec4f(0.5) // broadcast: (0.5, 0.5, 0.5, 0.5)
d.vec4f(rgb, 1) // vec3 + scalar (common: color + alpha)
d.vec4f(v2a, v2b) // two vec2s
d.vec4f(1, uv, 0) // scalar + vec2 + scalarSwizzles (, , , , etc.) return vector instances that work as constructor arguments: .
.xy.zw.rgb.bad.vec4f(pos.xy, vel.zw)Prefer these overloads over manual component decomposition. Instead of , write .
d.vec3f(v.x, v.y, newZ)d.vec3f(v.xy, newZ)ts
d.vec2f d.vec3f d.vec4f // f32 类型
d.vec2i d.vec3i d.vec4i // i32 类型
d.vec2u d.vec3u d.vec4u // u32 类型
d.vec2h d.vec3h d.vec4h // f16 类型
d.mat2x2f d.mat3x3f d.mat4x4f实例类型: -> , -> 。
d.vec3f()d.v3fd.mat4x4f()d.m4x4f向量构造函数支持丰富的重载——请充分利用。 它们可由任意标量和更小向量组合而成,只要组件总数符合要求:
ts
d.vec3f() // 零初始化:(0, 0, 0)
d.vec3f(1) // 广播:(1, 1, 1)
d.vec3f(1, 2, 3) // 单独指定组件
d.vec3f(someVec2, 1) // vec2 + 标量
d.vec3f(1, someVec2) // 标量 + vec2
d.vec4f() // 零初始化:(0, 0, 0, 0)
d.vec4f(0.5) // 广播:(0.5, 0.5, 0.5, 0.5)
d.vec4f(rgb, 1) // vec3 + 标量(常见:颜色 + 透明度)
d.vec4f(v2a, v2b) // 两个 vec2
d.vec4f(1, uv, 0) // 标量 + vec2 + 标量Swizzle(、、、 等)返回的向量实例可作为构造函数参数:。
.xy.zw.rgb.bad.vec4f(pos.xy, vel.zw)优先使用这些重载而非手动分解组件。 不要写 ,而是写 。
d.vec3f(v.x, v.y, newZ)d.vec3f(v.xy, newZ)Compound types
复合类型
ts
const Particle = d.struct({
position: d.vec2f,
velocity: d.vec2f,
color: d.vec4f,
});
const ParticleArray = d.arrayOf(Particle, 1000); // fixed-sizeRuntime-sized schemas. without a count returns a function . This dual nature is the key: pass the function itself (unsized) to bind group layouts, call it with a count (sized) for buffer creation.
d.arrayOf(Element)(n: number) => WgslArray<Element>ts
// Plain array - arrayOf without count is already a factory:
const layout = tgpu.bindGroupLayout({
data: { storage: d.arrayOf(d.f32), access: 'mutable' }, // unsized for layout
});
const buf = root.createBuffer(d.arrayOf(d.f32, 1024)).$usage('storage'); // sized for buffer
// Struct with a runtime-sized last field - wrap in a factory function:
const RuntimeStruct = (n: number) =>
d.struct({
counter: d.atomic(d.u32),
items: d.arrayOf(d.f32, n), // last field gets the runtime size
});
const layout2 = tgpu.bindGroupLayout({
runtimeData: { storage: RuntimeStruct, access: 'mutable' }, // unsized (the function)
});
const buf2 = root.createBuffer(RuntimeStruct(1024)).$usage('storage'); // sized (called)You cannot pass an unsized schema directly to - size must be known on the CPU.
createBufferts
const Particle = d.struct({
position: d.vec2f,
velocity: d.vec2f,
color: d.vec4f,
});
const ParticleArray = d.arrayOf(Particle, 1000); // 固定大小运行时大小的架构。 不带数量的 返回一个函数 。这种双重特性是关键:将函数本身(未指定大小)传递给绑定组布局,调用时传入数量(指定大小)以创建缓冲区。
d.arrayOf(Element)(n: number) => WgslArray<Element>ts
// 普通数组——不带数量的 arrayOf 本身就是工厂函数:
const layout = tgpu.bindGroupLayout({
data: { storage: d.arrayOf(d.f32), access: 'mutable' }, // 布局使用未指定大小的版本
});
const buf = root.createBuffer(d.arrayOf(d.f32, 1024)).$usage('storage'); // 缓冲区使用指定大小的版本
// 最后一个字段为运行时大小的结构体——包装为工厂函数:
const RuntimeStruct = (n: number) =>
d.struct({
counter: d.atomic(d.u32),
items: d.arrayOf(d.f32, n), // 最后一个字段使用运行时大小
});
const layout2 = tgpu.bindGroupLayout({
runtimeData: { storage: RuntimeStruct, access: 'mutable' }, // 未指定大小(传入函数)
});
const buf2 = root.createBuffer(RuntimeStruct(1024)).$usage('storage'); // 指定大小(调用函数)不能直接将未指定大小的架构传递给 ——CPU 必须知道大小。
createBufferGPU functions
GPU 函数
TypeGPU compiles TypeScript marked with into WGSL.
'use gpu'TypeGPU 会将标记有 的 TypeScript 代码编译为 WGSL。
'use gpu'Plain callback (polymorphic)
普通回调(多态)
No explicit signature; best for helper math and flexible utilities.
ts
const rotate = (v: d.v2f, angle: number) => {
'use gpu';
const c = std.cos(angle);
const s = std.sin(angle);
return d.vec2f(c * v.x - s * v.y, s * v.x + c * v.y);
};numberd.v2f | d.v3f无显式签名;最适合辅助数学计算和灵活的工具函数。
ts
const rotate = (v: d.v2f, angle: number) => {
'use gpu';
const c = std.cos(angle);
const s = std.sin(angle);
return d.vec2f(c * v.x - s * v.y, s * v.x + c * v.y);
};numberd.v2f | d.v3ftgpu.fn
(explicit types)
tgpu.fntgpu.fn
(显式类型)
tgpu.fnPinned WGSL signature. Use for library code or when you need a fixed WGSL interface.
ts
const rotate = tgpu.fn([d.vec2f, d.f32], d.vec2f)((v, angle) => {
'use gpu';
// ...
});固定的 WGSL 签名。适用于库代码或需要固定 WGSL 接口的场景。
ts
const rotate = tgpu.fn([d.vec2f, d.f32], d.vec2f)((v, angle) => {
'use gpu';
// ...
});Shader entrypoints
着色器入口点
ts
// Compute
const myCompute = tgpu.computeFn({
workgroupSize: [64],
in: { gid: d.builtin.globalInvocationId },
})((input) => { 'use gpu'; /* input.gid: d.v3u */ });
// Vertex
const myVertex = tgpu.vertexFn({
in: { position: d.vec3f, uv: d.vec2f },
out: { position: d.builtin.position, fragUv: d.vec2f },
})((input) => {
'use gpu';
return { position: d.vec4f(input.position, 1), fragUv: input.uv };
});
// Fragment
const myFragment = tgpu.fragmentFn({
in: { fragUv: d.vec2f },
out: d.vec4f,
})((input) => { 'use gpu'; return d.vec4f(input.fragUv, 0, 1); });Vertex may include builtins: , .
ind.builtin.vertexIndexd.builtin.instanceIndexFull shader syntax, branch pruning, the library, and type inference: see .
stdreferences/shaders.mdValues vs references — the most common source of . See .
ResolutionErrorreferences/shaders.mdIdiomatic patterns (vector ops, struct constructors, register pressure): see .
references/shaders.mdts
// 计算着色器
const myCompute = tgpu.computeFn({
workgroupSize: [64],
in: { gid: d.builtin.globalInvocationId },
})((input) => { 'use gpu'; /* input.gid: d.v3u */ });
// 顶点着色器
const myVertex = tgpu.vertexFn({
in: { position: d.vec3f, uv: d.vec2f },
out: { position: d.builtin.position, fragUv: d.vec2f },
})((input) => {
'use gpu';
return { position: d.vec4f(input.position, 1), fragUv: input.uv };
});
// 片段着色器
const myFragment = tgpu.fragmentFn({
in: { fragUv: d.vec2f },
out: d.vec4f,
})((input) => { 'use gpu'; return d.vec4f(input.fragUv, 0, 1); });顶点着色器的 可包含内置变量:、。
ind.builtin.vertexIndexd.builtin.instanceIndex完整的着色器语法、分支修剪、 库和类型推断:请查阅 。
stdreferences/shaders.md值 vs 引用——这是 最常见的原因。请查阅 。
ResolutionErrorreferences/shaders.md惯用模式(向量操作、结构体构造函数、寄存器压力):请查阅 。
references/shaders.mdBuffers
缓冲区
Creating
创建
ts
// Schema only:
const buf = root.createBuffer(d.arrayOf(Particle, 1000)).$usage('storage');
// With typed initial value (only when non-zero — all buffers are zero-initialized by default):
const uBuf = root.createBuffer(Config, { time: 1, scale: 2.0 }).$usage('uniform');
// With an initializer callback - buffer is still mapped (cheapest CPU path):
const buf = root.createBuffer(Schema, (mappedBuffer) => {
mappedBuffer.write([10, 20], { startOffset: firstChunk.offset });
mappedBuffer.write([30, 40], { startOffset: secondChunk.offset });
});
// Wrap an existing GPUBuffer (you own its lifecycle and flags):
const buf = root.createBuffer(d.u32, existingGPUBuffer);
buf.write(12);ts
// 仅指定架构:
const buf = root.createBuffer(d.arrayOf(Particle, 1000)).$usage('storage');
// 带类型初始值(仅非零值时使用——所有缓冲区默认零初始化):
const uBuf = root.createBuffer(Config, { time: 1, scale: 2.0 }).$usage('uniform');
// 带初始化回调——缓冲区仍处于映射状态(CPU 最快路径):
const buf = root.createBuffer(Schema, (mappedBuffer) => {
mappedBuffer.write([10, 20], { startOffset: firstChunk.offset });
mappedBuffer.write([30, 40], { startOffset: secondChunk.offset });
});
// 包装现有 GPUBuffer(你需负责其生命周期和标志):
const buf = root.createBuffer(d.u32, existingGPUBuffer);
buf.write(12);Usage flags
使用标志
| Literal | Shader access |
|---|---|
| |
| |
| vertex input, paired with |
| index buffer ( |
| indirect dispatch/draw |
All buffers get automatically. adds any flag not covered by .
COPY_SRC | COPY_DST$addFlags(GPUBufferUsage.X)$usage| 字面量 | 着色器访问权限 |
|---|---|
| |
| |
| 顶点输入,与 |
| 索引缓冲区(仅支持 |
| 间接调度/绘制 |
所有缓冲区会自动添加 。 可添加 未覆盖的任何标志。
COPY_SRC | COPY_DST$addFlags(GPUBufferUsage.X)$usageWriting
写入
.write(value)| Form | Example ( | Notes |
|---|---|---|
| Typed instance | | Allocates a wrapper — fine for setup/prototypes |
| Plain JS array / tuple | | No allocation, padding added automatically |
| TypedArray | | Bytes copied verbatim — must include WGSL padding |
| ArrayBuffer | | Maximum throughput, bytes copied verbatim |
Cache plain arrays or at setup and reuse. For the padding rules ( = 16 bytes, per-column padding) and full fast-path guidance, see .
Float32Arrayvec3fmat3x3freferences/matrices.mdSlice write - update a sub-region using to get byte offsets:
d.memoryLayoutOfts
const layout = d.memoryLayoutOf(schema, (a) => a[3]);
buffer.write([4, 5, 6], { startOffset: layout.offset });.patch(data)ts
planetBuffer.patch({
mass: 123.1,
colors: { 2: [1, 0, 0], 4: d.vec3f(0, 0, 1) },
});common.writeSoA(buffer, { field: Float32Array, ... })references/matrices.mdreferences/pipelines.mdGPU-side copy: (schemas must match).
destBuffer.copyFrom(srcBuffer).write(value)| 形式 | 示例( | 说明 |
|---|---|---|
| 类型化实例 | | 会分配包装器——适合设置/原型开发 |
| 普通 JS 数组/元组 | | 无分配,自动添加填充 |
| TypedArray | | 字节直接复制——必须包含 WGSL 填充 |
| ArrayBuffer | | 最大吞吐量,字节直接复制 |
在设置阶段缓存普通数组或 并复用。关于填充规则( = 16 字节, 按列填充)和完整的快速路径指南,请查阅 。
Float32Arrayvec3fmat3x3freferences/matrices.md切片写入——使用 获取字节偏移量来更新子区域:
d.memoryLayoutOfts
const layout = d.memoryLayoutOf(schema, (a) => a[3]);
buffer.write([4, 5, 6], { startOffset: layout.offset });.patch(data)ts
planetBuffer.patch({
mass: 123.1,
colors: { 2: [1, 0, 0], 4: d.vec3f(0, 0, 1) },
});common.writeSoA(buffer, { field: Float32Array, ... })references/matrices.mdreferences/pipelines.mdGPU 端复制: (架构必须匹配)。
destBuffer.copyFrom(srcBuffer)Reading
读取
ts
const data = await buffer.read(); // returns a typed JS value matching the schemats
const data = await buffer.read(); // 返回与架构匹配的类型化 JS 值Shorthand "fixed" resources
简写“固定”资源
Skip manual bind groups - the buffer is always bound when referenced in any shader:
ts
const particlesMutable = root.createMutable(d.arrayOf(Particle, 1000)); // var<storage, read_write>
const configUniform = root.createUniform(Config); // var<uniform>
const bufReadonly = root.createReadonly(d.arrayOf(d.f32, N)); // var<storage, read>Access inside shaders via , . Prefer fixed resources by default; switch to manual bind groups when you need to swap resources per frame, manage indices, or share layouts across pipelines.
particles.$config.$@group跳过手动绑定组——缓冲区在任何着色器中被引用时始终处于绑定状态:
ts
const particlesMutable = root.createMutable(d.arrayOf(Particle, 1000)); // var<storage, read_write>
const configUniform = root.createUniform(Config); // var<uniform>
const bufReadonly = root.createReadonly(d.arrayOf(d.f32, N)); // var<storage, read>在着色器中通过 、 访问。默认优先使用固定资源;当需要每帧交换资源、管理 索引或跨管线共享布局时,切换到手动绑定组。
particles.$config.$@groupBind group layouts (manual binding)
绑定组布局(手动绑定)
ts
const layout = tgpu.bindGroupLayout({
config: { uniform: ConfigSchema },
particles: { storage: d.arrayOf(Particle), access: 'mutable' },
mySampler: { sampler: 'filtering' }, // 'filtering' | 'non-filtering' | 'comparison'
myTexture: { texture: d.texture2d(d.f32) },
});
// Inside shaders: layout.$.config, layout.$.particles, ...
const bindGroup = root.createBindGroup(layout, {
config: configBuffer,
particles: particleBuffer,
mySampler: tgpuSampler,
myTexture: textureOrView,
});
pipeline.with(bindGroup).dispatchWorkgroups(N);Explicit index (only needed when integrating with raw WGSL that hardcodes group indices): .
@grouplayout.$idx(0)ts
const layout = tgpu.bindGroupLayout({
config: { uniform: ConfigSchema },
particles: { storage: d.arrayOf(Particle), access: 'mutable' },
mySampler: { sampler: 'filtering' }, // 'filtering' | 'non-filtering' | 'comparison'
myTexture: { texture: d.texture2d(d.f32) },
});
// 在着色器中:layout.$.config, layout.$.particles, ...
const bindGroup = root.createBindGroup(layout, {
config: configBuffer,
particles: particleBuffer,
mySampler: tgpuSampler,
myTexture: textureOrView,
});
pipeline.with(bindGroup).dispatchWorkgroups(N);显式 索引(仅当与硬编码组索引的原生 WGSL 集成时需要):。
@grouplayout.$idx(0)Compute pipelines
计算管线
ts
// Standard - you control workgroup sizing
const pipeline = root.createComputePipeline({ compute: myComputeFn });
pipeline.with(bindGroup).dispatchWorkgroups(Math.ceil(N / 64));
// Guarded - TypeGPU handles workgroup sizing and bounds checking automatically.
// The callback's parameter count sets the dimensionality (0D to 3D):
const p0 = root.createGuardedComputePipeline(() => { 'use gpu'; /* runs once */ });
const p1 = root.createGuardedComputePipeline((x: number) => { 'use gpu'; });
const p2 = root.createGuardedComputePipeline((x: number, y: number) => { 'use gpu'; });
const p3 = root.createGuardedComputePipeline((x: number, y: number, z: number) => { 'use gpu'; });
// dispatchThreads matches the callback's arity - pass thread counts, not workgroup counts.
// TypeGPU picks workgroup sizes internally and injects a bounds guard so threads
// outside the requested range are no-ops.
p2.with(bindGroup).dispatchThreads(width, height);
// WGSL builtins like globalInvocationId are NOT available - use the callback parameters instead.ts
// 标准模式——你控制工作组大小
const pipeline = root.createComputePipeline({ compute: myComputeFn });
pipeline.with(bindGroup).dispatchWorkgroups(Math.ceil(N / 64));
// 自动防护模式——TypeGPU 自动处理工作组大小和边界检查。
// 回调的参数数量决定维度(0D 到 3D):
const p0 = root.createGuardedComputePipeline(() => { 'use gpu'; /* 运行一次 */ });
const p1 = root.createGuardedComputePipeline((x: number) => { 'use gpu'; });
const p2 = root.createGuardedComputePipeline((x: number, y: number) => { 'use gpu'; });
const p3 = root.createGuardedComputePipeline((x: number, y: number, z: number) => { 'use gpu'; });
// dispatchThreads 匹配回调的参数数量——传递线程数,而非工作组数。
// TypeGPU 内部选择工作组大小并注入边界防护,超出请求范围的线程会执行空操作。
p2.with(bindGroup).dispatchThreads(width, height);
// 无法使用 WGSL 内置变量如 globalInvocationId——请改用回调参数。WebGPU coordinate conventions
WebGPU 坐标约定
WebGPU matches DirectX/Metal, not OpenGL/WebGL — porting tutorials verbatim causes subtle bugs:
- NDC z: , not
[0, 1]. A copy-pasted[-1, 1]clips the near plane. UsegluPerspective'swgpu-matrix(already targetsmat4.perspective), or[0, 1]for better depth precision.mat4.perspectiveReverseZ - Framebuffer is top-left,
(0, 0)down — opposite of OpenGL.+yin a fragment shader is pixel-space with this origin.d.builtin.position.xy - Texture UV is top-left. Do not pre-flip
(0, 0)—valready matches this.createImageBitmap - Matrices are column-major: takes columns. Inside shaders use
d.mat4x4f(c0, c1, c2, c3); plainmat.columns[c][r]is rejected. Composition:mat[i]. Seeprojection * view * model * position.references/matrices.md
WebGPU 与 DirectX/Metal 一致,而非 OpenGL/WebGL——直接移植教程会导致细微错误:
- NDC z 范围:,而非
[0, 1]。直接复制的[-1, 1]会裁剪近平面。使用gluPerspective的wgpu-matrix(已针对mat4.perspective优化),或使用[0, 1]获得更好的深度精度。mat4.perspectiveReverseZ - 帧缓冲区 为左上角,
(0, 0)方向向下——与 OpenGL 相反。片段着色器中的+y是此原点的像素空间坐标。d.builtin.position.xy - 纹理 UV 为左上角。不要预先翻转
(0, 0)——v已匹配此约定。createImageBitmap - 矩阵为列主序:接受列向量。在着色器中使用
d.mat4x4f(c0, c1, c2, c3);直接使用mat.columns[c][r]会被拒绝。组合顺序:mat[i]。请查阅projection * view * model * position。references/matrices.md
Render pipelines
渲染管线
ts
const pipeline = root.createRenderPipeline({
vertex: myVertex,
fragment: myFragment,
targets: { format: presentationFormat }, // single target - shorthand
primitive?: GPUPrimitiveState,
depthStencil?: GPUDepthStencilState,
multisample?: GPUMultisampleState,
});
pipeline
.with(bindGroup)
.withColorAttachment({
view: context,
// loadOp/storeOp/clearValue have defaults
})
.withDepthStencilAttachment({ /* ... */ })
.withIndexBuffer(indexBuffer) // enables .drawIndexed()
.draw(vertexCount, instanceCount /* optional */);Shell-less inline vertex/fragment lambdas are also valid for simple cases.
ts
const pipeline = root.createRenderPipeline({
vertex: myVertex,
fragment: myFragment,
targets: { format: presentationFormat }, // 单个目标——简写形式
primitive?: GPUPrimitiveState,
depthStencil?: GPUDepthStencilState,
multisample?: GPUMultisampleState,
});
pipeline
.with(bindGroup)
.withColorAttachment({
view: context,
// loadOp/storeOp/clearValue 有默认值
})
.withDepthStencilAttachment({ /* ... */ })
.withIndexBuffer(indexBuffer) // 启用 .drawIndexed()
.draw(vertexCount, instanceCount /* 可选 */);对于简单场景,也可使用无外壳的内联顶点/片段 lambda。
Multiple render targets (MRT)
多渲染目标(MRT)
Use a named record for fragment , pipeline , and — TypeScript enforces matching keys. Keys become WGSL struct field names verbatim; no -prefixes. Builtins () go in but do not appear in or .
outtargetswithColorAttachment$fragDepthouttargetswithColorAttachmentFull MRT example, per-target blend/writeMask config, and the footgun: see .
fragDepthreferences/pipelines.md为片段着色器的 、管线的 和 使用命名记录——TypeScript 会强制匹配键名。键名会直接成为 WGSL 结构体字段名;无需添加 前缀。内置变量()需放在 中,但不会出现在 或 中。
outtargetswithColorAttachment$fragDepthouttargetswithColorAttachment完整的 MRT 示例、每个目标的混合/写入掩码配置以及 的陷阱:请查阅 。
fragDepthreferences/pipelines.mdCache bind groups and views
缓存绑定组和视图
root.createBindGroup(...)texture.createView(...)constFor vertex buffer layouts, the attribs spread trick, and the helper: .
common.fullScreenTrianglereferences/pipelines.mdroot.createBindGroup(...)texture.createView(...)const关于顶点缓冲区布局、attribs 展开技巧和 辅助函数:请查阅 。
common.fullScreenTrianglereferences/pipelines.mdGPU-scoped variables
GPU 作用域变量
tgpu.workgroupVar(schema)tgpu.privateVar(schema)tgpu.const(schema, value).$references/shaders.mdtgpu.workgroupVar(schema)tgpu.privateVar(schema)tgpu.const(schema, value).$references/shaders.mdSlots
插槽
tgpu.slot<T>().with(slot, value)ts
const distFnSlot = tgpu.slot<(pos: d.v3f) => number>();
const rayMarcher = tgpu.computeFn({
workgroupSize: [64],
in: { gid: d.builtin.globalInvocationId },
})(({ gid }) => {
'use gpu';
const dist = distFnSlot.$(d.vec3f(gid)); // call the injected function
});
root
.with(distFnSlot, (pos) => {
'use gpu';
return std.length(pos - d.vec3f(0, 0, -5)) - 1.0; // sphere SDF
})
.createComputePipeline({ compute: rayMarcher });Scalar/vector slot with a default:
ts
const colorSlot = tgpu.slot(d.vec4f(1, 0, 0, 1));
pipeline.with(colorSlot, d.vec4f(0, 1, 0, 1)).draw(3);tgpu.slot<T>().with(slot, value)ts
const distFnSlot = tgpu.slot<(pos: d.v3f) => number>();
const rayMarcher = tgpu.computeFn({
workgroupSize: [64],
in: { gid: d.builtin.globalInvocationId },
})(({ gid }) => {
'use gpu';
const dist = distFnSlot.$(d.vec3f(gid)); // 调用注入的函数
});
root
.with(distFnSlot, (pos) => {
'use gpu';
return std.length(pos - d.vec3f(0, 0, -5)) - 1.0; // 球体 SDF
})
.createComputePipeline({ compute: rayMarcher });带默认值的标量/向量插槽:
ts
const colorSlot = tgpu.slot(d.vec4f(1, 0, 0, 1));
pipeline.with(colorSlot, d.vec4f(0, 1, 0, 1)).draw(3);Accessors
访问器
tgpu.accessor(schema, initial?)'use gpu'ts
const colorAccess = tgpu.accessor(d.vec3f);
// Fill with a uniform buffer:
root.with(colorAccess, colorUniform).createComputePipeline(...)
// Fill with a literal (inlined):
root.with(colorAccess, d.vec3f(1, 0, 0)).createComputePipeline(...)
// Fill with a GPU function:
root.with(colorAccess, () => { 'use gpu'; return computeColor(); }).createComputePipeline(...)Write access: .
tgpu.mutableAccessor(schema, initial?)tgpu.accessor(schema, initial?)'use gpu'ts
const colorAccess = tgpu.accessor(d.vec3f);
// 填充为 uniform 缓冲区:
root.with(colorAccess, colorUniform).createComputePipeline(...);
// 填充为字面量(内联):
root.with(colorAccess, d.vec3f(1, 0, 0)).createComputePipeline(...);
// 填充为 GPU 函数:
root.with(colorAccess, () => { 'use gpu'; return computeColor(); }).createComputePipeline(...);写入权限:。
tgpu.mutableAccessor(schema, initial?)Type utilities
类型工具
d.InferInput<typeof Schema>.write()d.InferGPU<typeof Schema>'use gpu'AnyData'typegpu'TgpuBufferTgpuUniformTgpuTexturereferences/types.mdd.InferInput<typeof Schema>.write()d.InferGPU<typeof Schema>'use gpu'AnyData'typegpu'TgpuBufferTgpuUniformTgpuTexturereferences/types.mdCommon pitfalls
常见陷阱
- Numeric literals: may strip ->
1.0. UseabstractInt. See types.md.d.f32(1) - Outer-scope captures are constants: not runtime-mutable. Use /
createUniform. See shaders.md.createMutable - TypedArray/ArrayBuffer alignment: bytes copied verbatim. elements are 16 bytes (12 + 4 padding). Plain arrays handle padding; typed arrays must include it.
vec3f - Integer division: on primitives is
a / b. Usef32/d.i32()for integer semantics. See types.md.d.u32() - Uninitialised variables: is invalid - always initialise so the type can be inferred:
let x;.let x = d.f32(0) - Ternary operators: runtime ternaries aren't supported. Use .
std.select(falseVal, trueVal, condition) - Fragment output is always , even for fewer-channel formats. A pipeline with
d.vec4fortargets: { format: 'r8unorm' }still requires'rg16float'andout: d.vec4f. WebGPU drops the unused channels.return d.vec4f(...)
- 数值字面量:可能被转换为
1.0。请使用abstractInt。查阅 types.md。d.f32(1) - 外部作用域捕获的值是常量:不可运行时修改。使用 /
createUniform。查阅 shaders.md。createMutable - TypedArray/ArrayBuffer 对齐:字节直接复制。元素占 16 字节(12 + 4 填充)。普通数组会处理填充;TypedArray 必须包含填充。
vec3f - 整数除法:基元类型的 是
a / b类型。如需整数语义,请使用f32/d.i32()。查阅 types.md。d.u32() - 未初始化变量:无效——必须始终初始化以便推断类型:
let x;。let x = d.f32(0) - 三元运算符:不支持运行时三元运算符。使用 。
std.select(falseVal, trueVal, condition) - 片段输出始终为 ,即使格式通道更少。目标格式为
d.vec4f或'r8unorm'的管线仍需'rg16float'并返回out: d.vec4f。WebGPU 会丢弃未使用的通道。d.vec4f(...)
Companion packages
配套包
-
- real PRNG (
@typegpu/noise), distributions (uniform, normal, hemisphere, ...), and Perlin noise (randf/perlin2d) with optional precomputed gradient caches (~10x speedups). Prefer over hand-rolled hashes. Seeperlin3d.references/noise.md -
- 2D/3D signed distance primitives (
@typegpu/sdf,sdDisk,sdBox2d,sdRoundedBox2d,sdBezier,sdSphere,sdBox3d,sdCapsule, ...) and operators (sdPlane,opUnion,opSmoothUnion,opSmoothDifference). AllopExtrudeX/Y/Zwith pinned types, callable directly fromtgpu.fn. For ray marching, UI masking, AA vector drawing. See'use gpu'.references/sdf.md -
- canonical math library for TypeGPU. TypeGPU vectors/matrices can be passed as
wgpu-matrixtodstcalls to avoid allocations. Seewgpu-matrixfor full integration patterns.references/matrices.md
-
- 真正的伪随机数生成器(
@typegpu/noise)、分布(均匀分布、正态分布、半球分布等)以及 2D/3D Perlin 噪声(randf/perlin2d),支持可选的预计算梯度缓存(速度提升约 10 倍)。优先使用此包而非手动实现的哈希函数。查阅perlin3d。references/noise.md -
- 2D/3D 有符号距离基本体(
@typegpu/sdf、sdDisk、sdBox2d、sdRoundedBox2d、sdBezier、sdSphere、sdBox3d、sdCapsule等)和运算符(sdPlane、opUnion、opSmoothUnion、opSmoothDifference)。所有函数均为带固定类型的opExtrudeX/Y/Z,可直接从tgpu.fn函数调用。适用于光线步进、UI 遮罩、抗锯齿矢量绘制。查阅'use gpu'。references/sdf.md -
- TypeGPU 的标准数学库。TypeGPU 的向量/矩阵可作为
wgpu-matrix参数传递给dst调用以避免分配。完整的集成模式请查阅wgpu-matrix。references/matrices.md