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

GPURenderPassEncoder.setVertexBuffer()

Methode

Legt den <code>GPUBuffer</code> für einen Vertex-Buffer-Slot fest (oder hebt ihn auf), aus dem nachfolgende Zeichenbefehle ihre Vertex-Daten lesen.

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

Signatur

GPURenderPassEncoder.prototype.setVertexBuffer(slot, buffer, offset, size)

Beschreibung

Mit setVertexBuffer() bindest du innerhalb eines Render-Passes einen Puffer mit Vertex-Daten (z. B. Positionen, Farben, UV-Koordinaten) an einen bestimmten Slot. Der Slot-Index entspricht der Position im Array vertex.buffers der Render-Pipeline, die mit setPipeline() gesetzt wurde. Dort legst du auch fest, wie die Bytes im Puffer interpretiert werden (arrayStride, attributes, stepMode).

Die Bindung bleibt für alle folgenden Aufrufe von draw(), drawIndexed(), drawIndirect() und drawIndexedIndirect() im selben Pass bestehen, bis du den Slot neu belegst. So kannst du etwa mehrere Objekte mit unterschiedlichen Puffern nacheinander zeichnen, ohne die Pipeline zu wechseln.

Mit offset und size kannst du nur einen Teil des Puffers binden. Das ist nützlich, wenn mehrere Meshes oder Attribut-Ströme in einem großen Puffer liegen. Übergibst du null als buffer, wird die Bindung des Slots aufgehoben.

Der Puffer muss mit dem Verwendungs-Flag GPUBufferUsage.VERTEX erstellt worden sein. Fehler werden nicht sofort geworfen, sondern machen den Encoder ungültig. Sichtbar werden sie erst beim end() bzw. finish() als Validierungsfehler.

Parameter

Name Typ Default Beschreibung
$slot Pflicht number Index des Vertex-Buffer-Slots (ganzzahlig, 0 bis device.limits.maxVertexBuffers - 1, meist 0–7). Entspricht dem Index in vertex.buffers des Pipeline-Deskriptors.
$buffer Pflicht GPUBuffer | null Der zu bindende Puffer mit Verwendung GPUBufferUsage.VERTEX. null hebt die Bindung des Slots auf.
$offset number 0 Startposition in Bytes innerhalb des Puffers. Muss ein Vielfaches von 4 sein.
$size number buffer.size - offset Anzahl der Bytes ab offset, die als Vertex-Daten gelten. Wenn du keinen Wert angibst, reicht der Bereich bis zum Pufferende.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined).

Beispiele

Dreieck mit einem Vertex-Buffer zeichnen

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

// x, y pro Vertex
const vertices = new Float32Array([0, 0.5, -0.5, -0.5, 0.5, -0.5]);
const vertexBuffer = device.createBuffer({
  size: vertices.byteLength,
  usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
});
device.queue.writeBuffer(vertexBuffer, 0, vertices);

const module = device.createShaderModule({ code: `
  @vertex fn vs(@location(0) pos: vec2f) -> @builtin(position) vec4f {
    return vec4f(pos, 0, 1);
  }
  @fragment fn fs() -> @location(0) vec4f { return vec4f(1, 0.4, 0, 1); }
`});

const pipeline = device.createRenderPipeline({
  layout: 'auto',
  vertex: {
    module, entryPoint: 'vs',
    buffers: [{ arrayStride: 8, attributes: [{ shaderLocation: 0, offset: 0, format: 'float32x2' }] }]
  },
  fragment: { module, entryPoint: 'fs', targets: [{ format }] }
});

const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({
  colorAttachments: [{ view: context.getCurrentTexture().createView(), loadOp: 'clear', storeOp: 'store', clearValue: { r: 0, g: 0, b: 0, a: 1 } }]
});
pass.setPipeline(pipeline);
pass.setVertexBuffer(0, vertexBuffer); // Slot 0 = buffers[0]
pass.draw(3);
pass.end();
device.queue.submit([encoder.finish()]);
Ein orangefarbenes Dreieck wird auf das Canvas gezeichnet.

Getrennte Puffer für Position und Farbe (zwei Slots)

// Pipeline-Ausschnitt: zwei Buffer-Layouts
const vertexBuffers = [
  { arrayStride: 8,  attributes: [{ shaderLocation: 0, offset: 0, format: 'float32x2' }] }, // Slot 0
  { arrayStride: 12, attributes: [{ shaderLocation: 1, offset: 0, format: 'float32x3' }] }  // Slot 1
];

// Im Render-Pass:
pass.setPipeline(pipeline);
pass.setVertexBuffer(0, positionBuffer);
pass.setVertexBuffer(1, colorBuffer);
pass.draw(3);

Mehrere Meshes aus einem gemeinsamen Puffer per Offset

// Ein großer Puffer enthält zwei Meshes hintereinander
const meshA = { offset: 0,   size: 96, count: 12 }; // 12 Vertices à 8 Byte
const meshB = { offset: 96,  size: 48, count: 6 };

pass.setPipeline(pipeline);
for (const mesh of [meshA, meshB]) {
  pass.setVertexBuffer(0, sharedBuffer, mesh.offset, mesh.size);
  pass.draw(mesh.count);
}

Instanzdaten in einem zweiten Slot

// Pipeline: buffers[1] hat stepMode: 'instance'
// Pro Instanz ein vec2f-Versatz (8 Byte)
const offsets = new Float32Array([-0.5, 0, 0, 0, 0.5, 0]);
const instanceBuffer = device.createBuffer({
  size: offsets.byteLength,
  usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
});
device.queue.writeBuffer(instanceBuffer, 0, offsets);

pass.setVertexBuffer(0, vertexBuffer);
pass.setVertexBuffer(1, instanceBuffer);
pass.draw(3, 3); // 3 Vertices, 3 Instanzen
Drei Dreiecke nebeneinander.

// Wichtig · Fallstricke

  • Verwendungs-Flag: Ohne GPUBufferUsage.VERTEX ist der Aufruf ungültig. Wenn du Daten mit queue.writeBuffer() hochladen willst, brauchst du zusätzlich COPY_DST.
  • Ausrichtung: offset und size müssen Vielfache von 4 sein, und offset + size darf buffer.size nicht überschreiten.
  • Slot-Limit: slot muss kleiner als device.limits.maxVertexBuffers sein (Standard: 8).
  • Fehler kommen verzögert: Ungültige Aufrufe werfen keine Ausnahme. Sie machen den Encoder ungültig, und der Fehler erscheint erst bei end() bzw. finish(). Zum Debuggen eignen sich device.pushErrorScope('validation') und popErrorScope().
  • Bindung muss zur Pipeline passen: Jeder Slot, den die aktuelle Pipeline in vertex.buffers beschreibt, muss vor draw() gebunden sein. Außerdem muss der gebundene Bereich groß genug für die Anzahl der Vertices bzw. Instanzen sein.
  • Indexpuffer getrennt: Indizes bindest du nicht hier, sondern mit setIndexBuffer().
  • Kompatibilität: WebGPU ist nur in sicheren Kontexten (HTTPS) verfügbar. Die Unterstützung in Firefox und Safari ist noch nicht auf allen Plattformen vollständig. Prüfe vorher mit if (!navigator.gpu), ob die API vorhanden ist.
  • Die Methode gibt es gleichnamig auch in GPURenderBundleEncoder.