Start · Sprachen · JavaScript · Referenz · GPURenderPassEncoder.setBindGroup()

GPURenderPassEncoder.setBindGroup()

Methode

Bindet eine <code>GPUBindGroup</code> an den angegebenen Gruppen-Index, sodass nachfolgende Draw-Aufrufe im Render-Pass auf deren Ressourcen zugreifen.

seit JavaScript WebGPU – Chrome/Edge 113+, Safari 26+, Firefox 141 Kategorie: webapi

Signatur

GPURenderPassEncoder.prototype.setBindGroup(index, bindGroup, dynamicOffsets?) / setBindGroup(index, bindGroup, dynamicOffsetsData, dynamicOffsetsDataStart, dynamicOffsetsDataLength)

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

Typ
undefined
Beschreibung
Kein Rückgabewert. Der Befehl wird im Encoder aufgezeichnet.

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()]);
Ein oranges Dreieck wird auf das Canvas gezeichnet.

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);
}