Start · Sprachen · JavaScript · Referenz · WebGLRenderingContext.stencilOp()

WebGLRenderingContext.stencilOp()

Methode

Legt fest, wie der Stencil-Buffer bei fehlgeschlagenem Stencil-Test, fehlgeschlagenem Tiefentest bzw. bestandenem Test verändert wird – für Vorder- und Rückseiten gleichzeitig.

seit JavaScript WebGL 1.0 – Baseline: alle modernen Browser Kategorie: webapi

Signatur

WebGLRenderingContext.prototype.stencilOp(fail, zfail, zpass)

Beschreibung

Die Methode stencilOp() bestimmt, was mit dem Wert im Stencil-Buffer passiert, nachdem für ein Fragment der Stencil- und der Tiefentest ausgewertet wurden. Es gibt drei Fälle: Der Stencil-Test schlägt fehl (fail), der Stencil-Test besteht, aber der Tiefentest schlägt fehl (zfail), oder beide Tests bestehen (zpass). Die Einstellung gilt sowohl für vorder- als auch für rückseitige Polygone.

Zusammen mit stencilFunc() (Vergleichsbedingung) und stencilMask() (Schreibmaske) ist stencilOp() die Grundlage für klassische Stencil-Techniken: Masken und Ausschnitte (Portale, Spiegel), Umrisse/Outlines, Schattenvolumen (Stencil Shadows) oder das Zählen von Überlagerungen.

Die Operation wirkt nur, wenn der Stencil-Test mit gl.enable(gl.STENCIL_TEST) aktiviert ist und der Zeichenpuffer überhaupt einen Stencil-Buffer besitzt – beim Standard-Framebuffer muss der Kontext dafür mit { stencil: true } erzeugt werden. Sollen Vorder- und Rückseiten unterschiedlich behandelt werden, verwendet man stattdessen stencilOpSeparate().

Mögliche Werte für alle drei Parameter: gl.KEEP (Standard, Wert bleibt), gl.ZERO (auf 0 setzen), gl.REPLACE (durch Referenzwert aus stencilFunc() ersetzen), gl.INCR / gl.DECR (um 1 erhöhen/verringern, an Grenzen gesättigt), gl.INCR_WRAP / gl.DECR_WRAP (erhöhen/verringern mit Überlauf) und gl.INVERT (bitweise invertieren).

Parameter

Name Typ Default Beschreibung
$fail Pflicht GLenum gl.KEEP Aktion, wenn der Stencil-Test fehlschlägt.
$zfail Pflicht GLenum gl.KEEP Aktion, wenn der Stencil-Test besteht, der Tiefentest aber fehlschlägt.
$zpass Pflicht GLenum gl.KEEP Aktion, wenn Stencil- und Tiefentest bestehen (oder kein Tiefentest aktiv ist).

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined).

Beispiele

Grundeinstellung setzen und abfragen

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl', { stencil: true });

gl.enable(gl.STENCIL_TEST);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);

// Aktuelle Einstellung auslesen
console.log(gl.getParameter(gl.STENCIL_FAIL) === gl.KEEP);
console.log(gl.getParameter(gl.STENCIL_PASS_DEPTH_PASS) === gl.REPLACE);
console.log(gl.getParameter(gl.STENCIL_BACK_PASS_DEPTH_PASS) === gl.REPLACE);
true true true

Maske zeichnen und Inhalt darauf beschränken

const gl = document.querySelector('canvas').getContext('webgl', { stencil: true });

// drawMask() und drawScene() seien eigene Zeichenfunktionen
const drawMask = () => { /* z. B. Kreis zeichnen */ };
const drawScene = () => { /* eigentliche Szene */ };

gl.clearStencil(0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
gl.enable(gl.STENCIL_TEST);

// 1. Durchgang: Maske in den Stencil-Buffer schreiben (Wert 1)
gl.stencilFunc(gl.ALWAYS, 1, 0xff);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
gl.colorMask(false, false, false, false); // keine Farbe schreiben
drawMask();

// 2. Durchgang: nur dort zeichnen, wo Stencil == 1
gl.colorMask(true, true, true, true);
gl.stencilFunc(gl.EQUAL, 1, 0xff);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); // Buffer nicht mehr verändern
drawScene();

Überlagerungen zählen

const gl = document.querySelector('canvas').getContext('webgl', { stencil: true });
const drawOverlappingQuads = () => { /* mehrere halbtransparente Flächen */ };

gl.enable(gl.STENCIL_TEST);
gl.clear(gl.STENCIL_BUFFER_BIT);

// Jedes gezeichnete Fragment erhöht den Zähler (gesättigt bei 255)
gl.stencilFunc(gl.ALWAYS, 0, 0xff);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.INCR);
drawOverlappingQuads();

// Danach z. B. nur Pixel mit mindestens 2 Überlagerungen hervorheben
gl.stencilFunc(gl.LEQUAL, 2, 0xff);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);

// Wichtig · Fallstricke

  • Kein Stencil-Buffer: WebGL erzeugt standardmäßig keinen Stencil-Buffer. Ohne getContext('webgl', { stencil: true }) (bzw. ein Renderbuffer mit DEPTH_STENCIL/STENCIL_INDEX8 beim eigenen Framebuffer) hat stencilOp() keinen sichtbaren Effekt. Prüfen mit gl.getContextAttributes().stencil oder gl.getParameter(gl.STENCIL_BITS).
  • Stencil-Test aktivieren: Ohne gl.enable(gl.STENCIL_TEST) wird der Buffer weder getestet noch verändert.
  • Schreibmaske beachten: stencilMask() begrenzt, welche Bits tatsächlich geschrieben werden – bei Maske 0x00 bleibt jede Operation wirkungslos.
  • Ungültige Werte erzeugen den Fehler gl.INVALID_ENUM (abfragbar mit gl.getError()); der Zustand bleibt dann unverändert.
  • INCR/DECR sättigen an 0 bzw. dem Maximalwert, INCR_WRAP/DECR_WRAP laufen über – für Schattenvolumen (Z-Fail/Carmack) sind die Wrap-Varianten meist die richtige Wahl.
  • Die Einstellung ist globaler Kontextzustand und bleibt bis zur nächsten Änderung bestehen – nach Stencil-Durchgängen ggf. auf KEEP, KEEP, KEEP zurücksetzen.
  • Verfügbar in allen Browsern mit WebGL-Unterstützung, ebenso in WebGL2RenderingContext.