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

WebGLRenderingContext.stencilFuncSeparate()

Methode

Legt Vergleichsfunktion, Referenzwert und Bitmaske für den Stencil-Test getrennt für Vorder- und/oder Rückseiten von Polygonen fest.

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

Signatur

WebGLRenderingContext.prototype.stencilFuncSeparate(face, func, ref, mask)

Beschreibung

stencilFuncSeparate() legt fest, wie der Stencil-Test entscheidet, ob ein Fragment gezeichnet wird. Anders als stencilFunc(), das beide Seiten gleich behandelt, kann man hier die Regeln für Vorderseiten (gl.FRONT) und Rückseiten (gl.BACK) getrennt setzen.

Beim Test wird (ref & mask) mit (stencilwert & mask) über die gewählte Vergleichsfunktion verglichen. Bei gl.LESS besteht das Fragment zum Beispiel, wenn (ref & mask) < (stencil & mask) gilt. Was danach mit dem Stencil-Puffer passiert, legt man mit stencilOp() bzw. stencilOpSeparate() fest.

Typische Einsatzfälle sind Techniken, die in einem Durchgang Vorder- und Rückseiten unterschiedlich auswerten: Stencil Shadow Volumes (Z-Pass/Z-Fail), Schnittflächen (Capping) bei Clipping-Ebenen oder das Markieren von Bereichen innerhalb geschlossener Körper. Der Stencil-Test wirkt nur, wenn er mit gl.enable(gl.STENCIL_TEST) eingeschaltet ist und der Zeichenpuffer einen Stencil-Puffer hat.

Parameter

Name Typ Default Beschreibung
$face Pflicht GLenum Für welche Seite die Einstellung gilt: gl.FRONT, gl.BACK oder gl.FRONT_AND_BACK.
$func Pflicht GLenum gl.ALWAYS Vergleichsfunktion: gl.NEVER, gl.LESS, gl.EQUAL, gl.LEQUAL, gl.GREATER, gl.NOTEQUAL, gl.GEQUAL oder gl.ALWAYS.
$ref Pflicht GLint 0 Referenzwert für den Vergleich. Er wird auf den Bereich 0 bis 2^n - 1 begrenzt, wobei n die Zahl der Stencil-Bits ist (meist 8).
$mask Pflicht GLuint 0xFFFFFFFF (alle Bits gesetzt) Bitmaske, die vor dem Vergleich per UND auf ref und den gespeicherten Stencil-Wert angewendet wird.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Bei ungültigen Werten für face oder func wird der Fehler gl.INVALID_ENUM gesetzt, den man mit gl.getError() abfragen kann.

Beispiele

Grundlegende Einrichtung für Vorder- und Rückseite

const canvas = document.querySelector('canvas');
// Stencil-Puffer muss explizit angefordert werden
const gl = canvas.getContext('webgl', { stencil: true });

gl.enable(gl.STENCIL_TEST);

// Vorderseiten: nur zeichnen, wo der Stencil-Wert 1 ist
gl.stencilFuncSeparate(gl.FRONT, gl.EQUAL, 1, 0xFF);
// Rückseiten: immer bestehen
gl.stencilFuncSeparate(gl.BACK, gl.ALWAYS, 0, 0xFF);

console.log(gl.getParameter(gl.STENCIL_FUNC) === gl.EQUAL);
console.log(gl.getParameter(gl.STENCIL_BACK_FUNC) === gl.ALWAYS);
true true

Stencil Shadow Volume (Z-Fail) in einem Durchgang

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

const renderShadowVolume = (drawVolume) => {
  gl.enable(gl.STENCIL_TEST);
  gl.enable(gl.DEPTH_TEST);
  gl.disable(gl.CULL_FACE);          // beide Seiten rastern
  gl.colorMask(false, false, false, false);
  gl.depthMask(false);

  // Test besteht für beide Seiten immer
  gl.stencilFuncSeparate(gl.FRONT_AND_BACK, gl.ALWAYS, 0, 0xFF);
  // Rückseite: bei Tiefentest-Fehler erhöhen, Vorderseite: verringern
  gl.stencilOpSeparate(gl.BACK, gl.KEEP, gl.INCR_WRAP, gl.KEEP);
  gl.stencilOpSeparate(gl.FRONT, gl.KEEP, gl.DECR_WRAP, gl.KEEP);

  drawVolume();

  // Beleuchtung nur dort, wo der Stencil-Wert 0 ist (nicht im Schatten)
  gl.colorMask(true, true, true, true);
  gl.stencilFuncSeparate(gl.FRONT_AND_BACK, gl.EQUAL, 0, 0xFF);
  gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
};

renderShadowVolume(() => { /* gl.drawArrays(...) für das Volumen */ });

Einzelne Bits mit einer Maske prüfen

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

// Bit 2 (Wert 4) kennzeichnet z. B. "Spiegelfläche" – nur Vorderseiten dort zeichnen
gl.stencilFuncSeparate(gl.FRONT, gl.EQUAL, 0b100, 0b100);
// Rückseiten nie zeichnen
gl.stencilFuncSeparate(gl.BACK, gl.NEVER, 0, 0xFF);

console.log(gl.getParameter(gl.STENCIL_VALUE_MASK));
console.log(gl.getParameter(gl.STENCIL_REF));
4 4

// Wichtig · Fallstricke

  • Stencil-Puffer anfordern: Der Standard-Zeichenpuffer hat keinen Stencil-Puffer. Ohne getContext('webgl', { stencil: true }) (oder einen Framebuffer mit STENCIL- bzw. DEPTH_STENCIL-Anhang) hat der Aufruf keine sichtbare Wirkung. Prüfen lässt sich das mit gl.getParameter(gl.STENCIL_BITS).
  • WebGL-Einschränkung: Anders als in OpenGL ES verlangt WebGL, dass ref und mask für Vorder- und Rückseite übereinstimmen (bezogen auf die tatsächlichen Stencil-Bits). Wenn nicht, erzeugen Zeichenaufrufe (drawArrays/drawElements) den Fehler gl.INVALID_OPERATION. Nur func darf sich zwischen den Seiten unterscheiden.
  • Welche Seite vorne ist, hängt von gl.frontFace() ab (Standard: gl.CCW). Wenn gl.CULL_FACE aktiv ist, werden verworfene Seiten gar nicht erst getestet.
  • Der Stencil-Test braucht gl.enable(gl.STENCIL_TEST). Den Puffer leert man mit gl.clearStencil() und gl.clear(gl.STENCIL_BUFFER_BIT).
  • Kompatibilität: Die Methode gibt es in allen Browsern mit WebGL 1 und genauso in WebGL2RenderingContext.