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

GPURenderPassEncoder.setStencilReference()

Methode

Legt den Stencil-Referenzwert eines Render-Passes fest. Stencil-Tests vergleichen gegen diesen Wert, und die Operation <code>"replace"</code> schreibt ihn in den Stencil-Puffer.

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

Signatur

GPURenderPassEncoder.prototype.setStencilReference(reference)

Beschreibung

setStencilReference() setzt den Stencil-Referenzwert für alle folgenden Zeichenbefehle im aktuellen GPURenderPassEncoder. Der Wert wird an zwei Stellen verwendet:

  • beim Stencil-Vergleich (stencilFront.compare / stencilBack.compare in depthStencil der Render-Pipeline), zum Beispiel "equal" oder "not-equal";
  • als Wert, den die Stencil-Operation "replace" (in passOp, failOp oder depthFailOp) in den Stencil-Puffer schreibt.

Der Referenzwert gehört zum Zustand des Render-Passes, nicht zur Pipeline. Er bleibt also gültig, wenn Sie mit setPipeline() die Pipeline wechseln. Genau deshalb ist er praktisch: Mit einer einzigen Pipeline können Sie verschiedene Objekte mit unterschiedlichen Stencil-IDs markieren, indem Sie vor jedem draw() einen anderen Referenzwert setzen. Zu Beginn jedes Render-Passes ist der Wert 0.

Typische Einsatzfälle sind Masken (zum Beispiel Portale, Spiegel, UI-Ausschnitte), Umriss- bzw. Outline-Effekte, das Markieren von Regionen für einen späteren Pass und Techniken wie Stencil-Schatten. Wirksam ist der Wert nur, wenn der Render-Pass ein Depth-Stencil-Attachment mit Stencil-Anteil hat, zum Beispiel "stencil8" oder "depth24plus-stencil8".

Parameter

Name Typ Default Beschreibung
$reference Pflicht number (GPUStencilValue, vorzeichenlose 32-Bit-Ganzzahl) Der neue Stencil-Referenzwert. Es zählen nur die unteren Bits, die das Stencil-Format tatsächlich hat, bei stencil8 also 0–255. Vor Vergleichen wird der Wert zusätzlich mit stencilReadMask verknüpft, beim Schreiben mit stencilWriteMask.

Rückgabewert

Typ
undefined
Beschreibung
Kein Rückgabewert. Der Befehl wird im Encoder aufgezeichnet und erst ausgeführt, wenn der Command-Buffer mit queue.submit() übermittelt wird.

Beispiele

Maske schreiben und anschließend nur innerhalb der Maske zeichnen

// Voraussetzung: device, context, maskModule, sceneModule sind bereits eingerichtet
const stencilTexture = device.createTexture({
  size: [canvas.width, canvas.height],
  format: 'stencil8',
  usage: GPUTextureUsage.RENDER_ATTACHMENT,
});

// Pipeline 1: schreibt den Referenzwert in den Stencil-Puffer, keine Farbe
const maskPipeline = device.createRenderPipeline({
  layout: 'auto',
  vertex: { module: maskModule, entryPoint: 'vs' },
  fragment: {
    module: maskModule,
    entryPoint: 'fs',
    targets: [{ format: navigator.gpu.getPreferredCanvasFormat(), writeMask: 0 }],
  },
  depthStencil: {
    format: 'stencil8',
    stencilFront: { compare: 'always', passOp: 'replace' },
    stencilBack: { compare: 'always', passOp: 'replace' },
  },
});

// Pipeline 2: zeichnet nur dort, wo Stencil == Referenzwert
const scenePipeline = device.createRenderPipeline({
  layout: 'auto',
  vertex: { module: sceneModule, entryPoint: 'vs' },
  fragment: {
    module: sceneModule,
    entryPoint: 'fs',
    targets: [{ format: navigator.gpu.getPreferredCanvasFormat() }],
  },
  depthStencil: {
    format: 'stencil8',
    stencilFront: { compare: 'equal' },
    stencilBack: { compare: 'equal' },
  },
});

const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({
  colorAttachments: [{
    view: context.getCurrentTexture().createView(),
    clearValue: [0, 0, 0, 1],
    loadOp: 'clear',
    storeOp: 'store',
  }],
  depthStencilAttachment: {
    view: stencilTexture.createView(),
    stencilClearValue: 0,
    stencilLoadOp: 'clear',
    stencilStoreOp: 'store',
  },
});

pass.setStencilReference(1);  // Maske = 1
pass.setPipeline(maskPipeline);
pass.draw(6);                 // z. B. ein Rechteck als Maske

pass.setPipeline(scenePipeline); // Referenzwert bleibt 1
pass.draw(3);                    // nur innerhalb der Maske sichtbar

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

Mehrere Objekte mit unterschiedlichen Stencil-IDs markieren

// Eine Pipeline mit passOp: 'replace' reicht für alle Objekte
const objects = [
  { id: 1, vertexCount: 36, bindGroup: bgCube },
  { id: 2, vertexCount: 96, bindGroup: bgSphere },
  { id: 3, vertexCount: 6, bindGroup: bgPlane },
];

pass.setPipeline(markPipeline);
for (const obj of objects) {
  pass.setStencilReference(obj.id); // ID pro Objekt
  pass.setBindGroup(0, obj.bindGroup);
  pass.draw(obj.vertexCount);
}
// Später lässt sich z. B. mit compare: 'equal' und Referenz 2
// nur die Kugel hervorheben (Outline-Effekt).

Wertebereich bei stencil8 beachten

// stencil8 hat nur 8 Bit – höhere Bits werden ignoriert
pass.setStencilReference(0xff);  // 255: größter sinnvoller Wert
pass.setStencilReference(256);   // wirkt wie 0 (nur untere 8 Bit zählen)

// Negative Werte sind unzulässig
try {
  pass.setStencilReference(-1);
} catch (err) {
  console.log(err.name);
}
TypeError

// Wichtig · Fallstricke

  • Zustand wird zurückgesetzt: Jeder neue Render-Pass beginnt mit dem Referenzwert 0. Der Wert gilt nicht über Passes hinweg und muss in jedem Pass neu gesetzt werden.
  • Kein Stencil-Attachment, keine Wirkung: Ohne Stencil-Anteil im depthStencilAttachment (zum Beispiel bei reinem "depth32float") gibt es keinen Fehler, der Wert wirkt aber einfach nicht.
  • Masken beachten: Beim Vergleich wird der Referenzwert mit stencilReadMask verknüpft, beim Schreiben mit stencilWriteMask. Ist die Schreibmaske 0, schreibt auch "replace" nichts.
  • Wertebereich: Der Parameter ist mit [EnforceRange] als vorzeichenlose 32-Bit-Ganzzahl deklariert. Negative oder zu große Werte lösen deshalb einen TypeError aus. Von den gültigen Werten zählen nur die Bits, die das Stencil-Format hat.
  • Vorder- und Rückseite: Es gibt nur einen Referenzwert für stencilFront und stencilBack. Getrennte Werte wie in OpenGL (glStencilFuncSeparate) sind nicht möglich.
  • Render-Bundles: GPURenderBundleEncoder hat diese Methode nicht. Setzen Sie den Referenzwert vor executeBundles() auf dem Pass-Encoder. Nach executeBundles() ist er allerdings wieder 0 und muss bei Bedarf erneut gesetzt werden.
  • Kompatibilität: WebGPU steht nur in sicheren Kontexten zur Verfügung. Prüfen Sie die Unterstützung vorab mit if (!navigator.gpu) { … }. Firefox und Safari unterstützen WebGPU erst in neueren Versionen und je nach Plattform.