Signatur
Beschreibung
setBindGroup() verknüpft eine zuvor mit GPUDevice.createBindGroup() erzeugte GPUBindGroup mit einem Gruppen-Index. Im WGSL-Shader entspricht dieser Index dem Attribut @group(n). Alle folgenden draw()-, drawIndexed()- und indirekten Draw-Aufrufe greifen auf die Puffer, Texturen und Sampler dieser Gruppe zu – bis die Gruppe am selben Index durch einen weiteren Aufruf ersetzt wird.
Üblich ist es, Ressourcen nach Änderungshäufigkeit aufzuteilen: zum Beispiel Gruppe 0 für Kamera- und Szenendaten (einmal pro Frame), Gruppe 1 für Materialien und Gruppe 2 für Daten pro Objekt. So muss zwischen zwei Draw-Aufrufen nur die Gruppe ausgetauscht werden, die sich tatsächlich ändert.
Hat das Bind-Group-Layout Einträge mit hasDynamicOffset: true, übergibt man zusätzlich dynamische Offsets. Damit lässt sich ein einziger großer Uniform- oder Storage-Puffer für viele Objekte verwenden, ohne für jedes Objekt eine eigene Bind Group anzulegen. Die Offsets gibt man entweder als normales Array an oder, ohne zusätzliche Speicherzuweisung, als Ausschnitt aus einem Uint32Array.
Die Methode schreibt nur einen Befehl in den Encoder. Ausgeführt wird er erst, wenn der erzeugte GPUCommandBuffer mit GPUQueue.submit() abgeschickt wird.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $index Pflicht | number | Gruppen-Index, entspricht @group(index) im Shader. Muss kleiner als device.limits.maxBindGroups sein (mindestens 4). |
|
| $bindGroup Pflicht | GPUBindGroup | null | Die zu bindende Gruppe. Mit null wird eine vorher gebundene Gruppe am Index entfernt (neuere Spezifikationen). |
|
| $dynamicOffsets | Iterable<number> | [] | Offsets in Bytes, einer pro Eintrag mit hasDynamicOffset: true, in der Reihenfolge der binding-Nummern. Jeder Offset muss ein Vielfaches von minUniformBufferOffsetAlignment bzw. minStorageBufferOffsetAlignment sein (meist 256). |
| $dynamicOffsetsData | Uint32Array | Alternative Form: ein Uint32Array, das die Offsets enthält. |
|
| $dynamicOffsetsDataStart | number | Index des ersten Elements in dynamicOffsetsData, das als Offset verwendet wird. |
|
| $dynamicOffsetsDataLength | number | Anzahl der Offsets, die aus dynamicOffsetsData gelesen werden. |
Rückgabewert
Beispiele
Einfache Uniform-Bind-Group für ein Dreieck
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const context = document.querySelector('canvas').getContext('webgpu');
const format = navigator.gpu.getPreferredCanvasFormat();
context.configure({ device, format });
const module = device.createShaderModule({ code: `
@group(0) @binding(0) var<uniform> color : vec4f;
@vertex fn vs(@builtin(vertex_index) i : u32) -> @builtin(position) vec4f {
var p = array(vec2f(0, 0.5), vec2f(-0.5, -0.5), vec2f(0.5, -0.5));
return vec4f(p[i], 0, 1);
}
@fragment fn fs() -> @location(0) vec4f { return color; }
` });
const pipeline = device.createRenderPipeline({
layout: 'auto',
vertex: { module, entryPoint: 'vs' },
fragment: { module, entryPoint: 'fs', targets: [{ format }] }
});
const uniformBuffer = device.createBuffer({
size: 16,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
device.queue.writeBuffer(uniformBuffer, 0, new Float32Array([1, 0.4, 0, 1]));
const bindGroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [{ binding: 0, resource: { buffer: uniformBuffer } }]
});
const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
loadOp: 'clear', storeOp: 'store', clearValue: [0, 0, 0, 1]
}]
});
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup); // @group(0)
pass.draw(3);
pass.end();
device.queue.submit([encoder.finish()]);
Dynamische Offsets: viele Objekte aus einem Puffer
// Voraussetzung: device, pipeline mit explizitem Layout, pass (aktiver Render-Pass)
const ALIGN = device.limits.minUniformBufferOffsetAlignment; // meist 256
const objectCount = 100;
const layout = device.createBindGroupLayout({
entries: [{
binding: 0,
visibility: GPUShaderStage.VERTEX,
buffer: { type: 'uniform', hasDynamicOffset: true }
}]
});
const objectBuffer = device.createBuffer({
size: ALIGN * objectCount,
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
});
const objectBindGroup = device.createBindGroup({
layout,
// size = Größe EINES Objekt-Blocks, nicht des ganzen Puffers
entries: [{ binding: 0, resource: { buffer: objectBuffer, size: 64 } }]
});
for (let i = 0; i < objectCount; i++) {
pass.setBindGroup(1, objectBindGroup, [i * ALIGN]);
pass.draw(36);
}
Offsets aus einem Uint32Array ohne neue Arrays
// Offsets für alle Objekte einmal vorberechnen
const offsets = new Uint32Array(objectCount);
for (let i = 0; i < objectCount; i++) offsets[i] = i * ALIGN;
for (let i = 0; i < objectCount; i++) {
// liest 1 Offset ab Position i, erzeugt pro Draw-Aufruf kein neues Array
pass.setBindGroup(1, objectBindGroup, offsets, i, 1);
pass.draw(36);
}