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

GPURenderBundleEncoder.setVertexBuffer()

Methode

Setzt oder entfernt den <code>GPUBuffer</code>, der an einem bestimmten Slot die Vertex-Daten für nachfolgende Zeichenbefehle eines Render-Bundles liefert.

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

Signatur

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

Beschreibung

Mit setVertexBuffer() bindest du beim Aufzeichnen eines Render-Bundles einen GPUBuffer an einen Vertex-Buffer-Slot. Welcher Slot welche Daten liefert, legt das Array vertex.buffers im Deskriptor der GPURenderPipeline fest: Der Index im Array entspricht dem slot-Parameter. Alle folgenden draw()- und drawIndexed()-Aufrufe im Bundle lesen ihre Vertex-Attribute aus diesem Buffer.

Render-Bundles (GPURenderBundle) sind vorab aufgezeichnete Befehlsfolgen, die du mit GPURenderPassEncoder.executeBundles() in beliebig vielen Render-Passes wiederverwenden kannst. Das spart CPU-Aufwand bei statischen Szenen, weil Validierung und Kodierung nur einmal stattfinden. Deshalb gehören die Vertex-Buffer-Bindungen direkt ins Bundle – ein Bundle erbt keinen Zustand aus dem umgebenden Render-Pass.

Mit offset und size kannst du nur einen Teilbereich des Buffers binden, etwa wenn mehrere Meshes in einem gemeinsamen großen Buffer liegen. Übergibst du null als buffer, wird die Bindung für diesen Slot entfernt.

Parameter

Name Typ Default Beschreibung
$slot Pflicht number Index des Vertex-Buffer-Slots (GPUIndex32). Entspricht dem Index in vertex.buffers der Pipeline; muss kleiner als device.limits.maxVertexBuffers sein (meist 8).
$buffer Pflicht GPUBuffer | null Der Buffer mit den Vertex-Daten. Muss mit GPUBufferUsage.VERTEX erstellt worden sein. null entfernt die Bindung des Slots.
$offset number 0 Byte-Offset im Buffer, ab dem die Vertex-Daten beginnen. Muss ein Vielfaches von 4 sein.
$size number buffer.size - offset Größe des gebundenen Bereichs in Bytes. offset + size darf buffer.size nicht überschreiten; muss ein Vielfaches von 4 sein.

Rückgabewert

Typ
undefined
Beschreibung
Kein Rückgabewert. Der Befehl wird in das Render-Bundle aufgezeichnet.

Beispiele

Dreieck in ein Render-Bundle aufzeichnen und ausführen

const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const canvas = document.querySelector('canvas');
const context = canvas.getContext('webgpu');
const format = navigator.gpu.getPreferredCanvasFormat();
context.configure({ device, format });

// Vertex-Daten: x, y pro Eckpunkt
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.0, 1.0);
    }
    @fragment fn fs() -> @location(0) vec4f {
      return vec4f(1.0, 0.4, 0.0, 1.0);
    }`
});

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

// Bundle aufzeichnen
const bundleEncoder = device.createRenderBundleEncoder({ colorFormats: [format] });
bundleEncoder.setPipeline(pipeline);
bundleEncoder.setVertexBuffer(0, vertexBuffer);
bundleEncoder.draw(3);
const bundle = bundleEncoder.finish();

// Bundle in einem Render-Pass ausführen
const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({
  colorAttachments: [{
    view: context.getCurrentTexture().createView(),
    loadOp: 'clear',
    clearValue: { r: 0, g: 0, b: 0, a: 1 },
    storeOp: 'store'
  }]
});
pass.executeBundles([bundle]);
pass.end();
device.queue.submit([encoder.finish()]);
Ein orangefarbenes Dreieck wird auf das Canvas gezeichnet.

Mehrere Meshes aus einem gemeinsamen Buffer per offset/size

// Annahme: device, pipeline, format wie oben; zwei Dreiecke in einem Buffer
const data = new Float32Array([
  // Mesh A (3 Vertices à 8 Byte = 24 Byte)
  -0.9, 0.9, -0.9, 0.1, -0.1, 0.1,
  // Mesh B
  0.1, -0.1, 0.9, -0.1, 0.5, -0.9
]);
const sharedBuffer = device.createBuffer({
  size: data.byteLength,
  usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
});
device.queue.writeBuffer(sharedBuffer, 0, data);

const meshBytes = 3 * 2 * Float32Array.BYTES_PER_ELEMENT; // 24
const be = device.createRenderBundleEncoder({ colorFormats: [format] });
be.setPipeline(pipeline);

be.setVertexBuffer(0, sharedBuffer, 0, meshBytes);         // Mesh A
be.draw(3);
be.setVertexBuffer(0, sharedBuffer, meshBytes, meshBytes); // Mesh B
be.draw(3);

const sceneBundle = be.finish();
console.log(sceneBundle instanceof GPURenderBundle);
true

Positionen und Farben in zwei Slots

// Pipeline mit zwei Vertex-Buffer-Layouts: Slot 0 = Position, Slot 1 = Farbe
const positions = new Float32Array([0, 0.5, -0.5, -0.5, 0.5, -0.5]);
const colors = new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]);

const makeVB = (arr) => {
  const buf = device.createBuffer({
    size: arr.byteLength,
    usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
  });
  device.queue.writeBuffer(buf, 0, arr);
  return buf;
};
const posBuffer = makeVB(positions);
const colorBuffer = makeVB(colors);

// colorPipeline: vertex.buffers = [
//   { arrayStride: 8,  attributes: [{ shaderLocation: 0, offset: 0, format: 'float32x2' }] },
//   { arrayStride: 12, attributes: [{ shaderLocation: 1, offset: 0, format: 'float32x3' }] }
// ]
const enc = device.createRenderBundleEncoder({ colorFormats: [format] });
enc.setPipeline(colorPipeline);
enc.setVertexBuffer(0, posBuffer);
enc.setVertexBuffer(1, colorBuffer);
enc.draw(3);
const colorBundle = enc.finish();