Signatur
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
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);
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 beifinish()als Validierungsfehler und lässt sich überdevice.pushErrorScope('validation')abfangen. - Ausrichtung:
offsetmuss ein Vielfaches von 2 (uint16) bzw. 4 (uint32) sein. FürwriteBuffer()muss die Puffergröße außerdem ein Vielfaches von 4 sein. Runde deshalb bei einer ungeraden Anzahl vonuint16-Indizes auf. - Strip-Topologien: Bei
line-stripodertriangle-stripmussstripIndexFormatder Pipeline gleichindexFormatsein. Den Index0xFFFFbzw.0xFFFFFFFFbehandelt 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.