Start · Sprachen · JavaScript · Referenz · GPURenderBundleEncoder.setIndexBuffer()

GPURenderBundleEncoder.setIndexBuffer()

Methode

Legt den <code>GPUBuffer</code> fest, aus dem nachfolgende <code>drawIndexed()</code>-Befehle im Render-Bundle ihre Indexdaten lesen.

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

Signatur

GPURenderBundleEncoder.prototype.setIndexBuffer(buffer, indexFormat, offset, size)

Beschreibung

Mit setIndexBuffer() bindest du einen Indexpuffer an einen GPURenderBundleEncoder. Indizierte Zeichenbefehle wie drawIndexed() und drawIndexedIndirect(), die du danach im selben Bundle aufzeichnest, lesen ihre Vertex-Indizes aus diesem Puffer. So kannst du gemeinsam genutzte Eckpunkte (etwa bei Würfeln oder Gittern) nur einmal im Vertexpuffer speichern und über Indizes mehrfach verwenden.

Render-Bundles sind vorab aufgezeichnete Befehlsfolgen. Du führst sie später mit GPURenderPassEncoder.executeBundles() in beliebig vielen Render-Passes aus. Ein Indexpuffer, den du im Bundle setzt, gilt nur innerhalb dieses Bundles. Er wird weder vom umgebenden Render-Pass übernommen noch an ihn weitergegeben.

Das indexFormat muss zu den Daten im Puffer passen: "uint16" spart Speicher bei bis zu 65 535 Eckpunkten, "uint32" ist für größere Meshes gedacht. Bei Topologien mit Strips ("line-strip", "triangle-strip") muss außerdem primitive.stripIndexFormat der Pipeline mit diesem Format übereinstimmen.

Parameter

Name Typ Default Beschreibung
$buffer Pflicht GPUBuffer Der Puffer mit den Indexdaten. Er muss mit dem Verwendungsflag GPUBufferUsage.INDEX erstellt worden sein.
$indexFormat Pflicht "uint16" | "uint32" Datenformat der Indizes: vorzeichenlose 16-Bit- oder 32-Bit-Ganzzahlen.
$offset number 0 Startposition der Indexdaten im Puffer, in Bytes. Muss ein Vielfaches der Indexgröße sein (2 bei uint16, 4 bei uint32).
$size number buffer.size - offset Größe des verwendeten Bereichs in Bytes. Ohne Angabe wird der Rest des Puffers ab offset verwendet.

Rückgabewert

Typ
undefined
Beschreibung
Kein Rückgabewert. Validierungsfehler werden nicht sofort geworfen, sondern machen den Encoder ungültig. Sie treten erst bei finish() bzw. beim Absenden auf.

Beispiele

Indexpuffer erstellen und im Render-Bundle binden

const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const format = navigator.gpu.getPreferredCanvasFormat();

// Indizes für ein Rechteck aus zwei Dreiecken
const indices = new Uint16Array([0, 1, 2, 2, 1, 3]);
const indexBuffer = device.createBuffer({
  size: Math.ceil(indices.byteLength / 4) * 4, // auf 4 Bytes ausrichten
  usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(indexBuffer, 0, indices);

const bundleEncoder = device.createRenderBundleEncoder({
  colorFormats: [format],
});
bundleEncoder.setPipeline(pipeline); // zuvor erstellte GPURenderPipeline
bundleEncoder.setVertexBuffer(0, vertexBuffer);
bundleEncoder.setIndexBuffer(indexBuffer, 'uint16');
bundleEncoder.drawIndexed(indices.length);

const bundle = bundleEncoder.finish();
console.log(bundle instanceof GPURenderBundle);
true

Bundle in einem Render-Pass ausführen

const commandEncoder = device.createCommandEncoder();
const pass = commandEncoder.beginRenderPass({
  colorAttachments: [{
    view: context.getCurrentTexture().createView(),
    clearValue: { r: 0, g: 0, b: 0, a: 1 },
    loadOp: 'clear',
    storeOp: 'store',
  }],
});

// Das Bundle bringt seinen eigenen Indexpuffer mit
pass.executeBundles([bundle]);
pass.end();
device.queue.submit([commandEncoder.finish()]);

Mehrere Meshes aus einem gemeinsamen Puffer mit offset und size

// Ein Puffer enthält die uint32-Indizes zweier Meshes hintereinander
const meshA = new Uint32Array([0, 1, 2, 0, 2, 3]);
const meshB = new Uint32Array([4, 5, 6]);
const shared = device.createBuffer({
  size: meshA.byteLength + meshB.byteLength,
  usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(shared, 0, meshA);
device.queue.writeBuffer(shared, meshA.byteLength, meshB);

const enc = device.createRenderBundleEncoder({ colorFormats: [format] });
enc.setPipeline(pipeline);
enc.setVertexBuffer(0, vertexBuffer);

enc.setIndexBuffer(shared, 'uint32', 0, meshA.byteLength);
enc.drawIndexed(meshA.length);

enc.setIndexBuffer(shared, 'uint32', meshA.byteLength, meshB.byteLength);
enc.drawIndexed(meshB.length);

const multiBundle = enc.finish();

// Wichtig · Fallstricke

  • Verwendungsflag: Fehlt beim Erstellen GPUBufferUsage.INDEX, ist der Aufruf ungültig. Der Fehler zeigt sich erst bei finish() als Validierungsfehler und lässt sich über device.pushErrorScope('validation') abfangen.
  • Ausrichtung: offset muss ein Vielfaches von 2 (uint16) bzw. 4 (uint32) sein. Für writeBuffer() muss die Puffergröße außerdem ein Vielfaches von 4 sein. Runde deshalb bei einer ungeraden Anzahl von uint16-Indizes auf.
  • Strip-Topologien: Bei line-strip oder triangle-strip muss stripIndexFormat der Pipeline gleich indexFormat sein. Den Index 0xFFFF bzw. 0xFFFFFFFF behandelt die GPU dann als Neustart des Strips (Primitive Restart).
  • Geltungsbereich: Der Zustand eines Bundles ist abgeschlossen. Nach executeBundles() sind Pipeline, Vertex- und Indexpuffer des Render-Passes zurückgesetzt und müssen bei Bedarf neu gesetzt werden.
  • Kompatibilität: WebGPU steht nur in sicheren Kontexten zur Verfügung. Die Browser-Unterstützung wächst noch. Prüfe vorab mit if (!navigator.gpu) und sieh bei Bedarf einen Ersatzweg (z. B. WebGL) vor.