Start · Sprachen · JavaScript · Referenz · GPURenderPassEncoder

GPURenderPassEncoder

Schnittstelle

Kodiert Zeichenbefehle für einen Render-Durchlauf: Pipeline, Bind-Groups und Vertex-/Index-Puffer setzen und mit <code>draw()</code> die Vertex- und Fragment-Shader ausführen.

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

Signatur

interface GPURenderPassEncoder

Beschreibung

GPURenderPassEncoder ist das Objekt, über das du in WebGPU die Befehle für einen Render-Durchlauf (Render Pass) aufzeichnest. Du erhältst es nie über einen Konstruktor, sondern immer über GPUCommandEncoder.beginRenderPass(descriptor). Im Deskriptor legst du fest, in welche Farb- und Tiefen-/Stencil-Anhänge (meist Texturen des Canvas-Kontexts) gezeichnet wird und ob sie vorher geleert (loadOp: "clear") oder erhalten werden.

Innerhalb des Durchlaufs setzt du den Zustand und löst Zeichenaufrufe aus. Die wichtigsten Methoden sind:

  • setPipeline(pipeline) – aktive GPURenderPipeline festlegen.
  • setBindGroup(index, bindGroup, dynamicOffsets?) – Ressourcen (Uniform-Puffer, Texturen, Sampler) binden.
  • setVertexBuffer(slot, buffer, offset?, size?) und setIndexBuffer(buffer, format, offset?, size?) – Geometriedaten binden.
  • draw(vertexCount, instanceCount?, firstVertex?, firstInstance?), drawIndexed(...), drawIndirect(...), drawIndexedIndirect(...) – Zeichenaufrufe.
  • setViewport(), setScissorRect(), setBlendConstant(), setStencilReference() – dynamischer Rasterzustand.
  • beginOcclusionQuery()/endOcclusionQuery(), executeBundles(), Debug-Marker (pushDebugGroup(), popDebugGroup(), insertDebugMarker()) sowie die Eigenschaft label.
  • end() – schließt den Durchlauf ab; erst danach kann der Command-Encoder weiterverwendet bzw. mit finish() abgeschlossen werden.

Die Befehle werden nicht sofort ausgeführt, sondern nur aufgezeichnet. Erst wenn der mit commandEncoder.finish() erzeugte GPUCommandBuffer über device.queue.submit() übergeben wird, arbeitet die GPU sie ab. Pro Frame erzeugst du typischerweise einen neuen Command-Encoder und einen neuen Render-Pass-Encoder – beide sind Einweg-Objekte.

Parameter

Name Typ Default Beschreibung
$descriptor Pflicht GPURenderPassDescriptor Wird an GPUCommandEncoder.beginRenderPass() übergeben. Enthält colorAttachments (Array mit view, loadOp, storeOp, clearValue), optional depthStencilAttachment, occlusionQuerySet, timestampWrites, maxDrawCount und label.

Rückgabewert

Typ
GPURenderPassEncoder
Beschreibung
Der von beginRenderPass() gelieferte Encoder, über den die Render-Befehle bis zum Aufruf von end() aufgezeichnet werden.

Beispiele

Render-Pass erzeugen und Canvas leeren

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

const commandEncoder = device.createCommandEncoder();

// Render-Pass-Encoder erzeugen – kein Konstruktor!
const pass = commandEncoder.beginRenderPass({
  label: 'Clear-Pass',
  colorAttachments: [{
    view: context.getCurrentTexture().createView(),
    clearValue: { r: 0.1, g: 0.2, b: 0.3, a: 1 },
    loadOp: 'clear',
    storeOp: 'store'
  }]
});

console.log(pass instanceof GPURenderPassEncoder, pass.label);
pass.end();

device.queue.submit([commandEncoder.finish()]);
true "Clear-Pass"

Dreieck zeichnen mit setPipeline() und draw()

const shader = device.createShaderModule({
  code: `
    @vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {
      var pos = array<vec2f, 3>(vec2f(0, 0.5), vec2f(-0.5, -0.5), vec2f(0.5, -0.5));
      return vec4f(pos[i], 0, 1);
    }
    @fragment fn fs() -> @location(0) vec4f {
      return vec4f(1, 0.4, 0, 1);
    }`
});

const pipeline = device.createRenderPipeline({
  layout: 'auto',
  vertex: { module: shader, entryPoint: 'vs' },
  fragment: { module: shader, entryPoint: 'fs', targets: [{ format }] }
});

const render = () => {
  const encoder = device.createCommandEncoder();
  const pass = encoder.beginRenderPass({
    colorAttachments: [{
      view: context.getCurrentTexture().createView(),
      clearValue: [0, 0, 0, 1],
      loadOp: 'clear',
      storeOp: 'store'
    }]
  });
  pass.setPipeline(pipeline);
  pass.draw(3); // 3 Vertices, 1 Instanz
  pass.end();
  device.queue.submit([encoder.finish()]);
  requestAnimationFrame(render);
};
requestAnimationFrame(render);

Indiziertes Zeichnen mit Vertex-/Index-Puffer, Bind-Group und Viewport

// Annahme: pipeline, vertexBuffer, indexBuffer, uniformBindGroup existieren
const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({
  colorAttachments: [{
    view: context.getCurrentTexture().createView(),
    loadOp: 'clear',
    storeOp: 'store',
    clearValue: [1, 1, 1, 1]
  }],
  depthStencilAttachment: {
    view: depthTexture.createView(),
    depthClearValue: 1.0,
    depthLoadOp: 'clear',
    depthStoreOp: 'store'
  }
});

pass.pushDebugGroup('Mesh zeichnen');
pass.setPipeline(pipeline);
pass.setViewport(0, 0, canvas.width, canvas.height, 0, 1);
pass.setBindGroup(0, uniformBindGroup);
pass.setVertexBuffer(0, vertexBuffer);
pass.setIndexBuffer(indexBuffer, 'uint16');
pass.drawIndexed(36, 10); // 36 Indizes, 10 Instanzen
pass.popDebugGroup();
pass.end();

device.queue.submit([encoder.finish()]);