Signatur
Beschreibung
stencilFunc() bestimmt, wann ein Fragment den Stencil-Test besteht. Für jedes Fragment wird (ref & mask) über die gewählte Vergleichsfunktion mit (stencilWert & mask) verglichen. stencilWert ist dabei der Wert, der an dieser Pixelposition schon im Stencil-Puffer steht. Besteht das Fragment den Test nicht, wird es verworfen.
Die Methode gilt für Vorder- und Rückseiten zugleich. Brauchen Sie für beide Seiten unterschiedliche Einstellungen, zum Beispiel für Stencil-Schatten-Volumen, nehmen Sie stencilFuncSeparate().
Typische Einsatzgebiete sind Masken (nur innerhalb einer bestimmten Form zeichnen), Umrisse bei ausgewählten Objekten, Spiegelungen und Portale. Meist kombinieren Sie die Methode mit stencilOp() (was bei bestandenem oder nicht bestandenem Test in den Puffer geschrieben wird) und mit stencilMask() (welche Bits überhaupt beschrieben werden dürfen).
Wichtig: Der Stencil-Test wirkt nur, wenn er mit gl.enable(gl.STENCIL_TEST) eingeschaltet ist und der Zeichenpuffer einen Stencil-Puffer hat. Den bekommen Sie mit getContext('webgl', { stencil: true }) oder mit einem Framebuffer, an den ein DEPTH_STENCIL- bzw. STENCIL_INDEX8-Renderbuffer angehängt ist.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $func Pflicht | GLenum | gl.ALWAYS | Vergleichsfunktion: gl.NEVER, gl.LESS, gl.EQUAL, gl.LEQUAL, gl.GREATER, gl.NOTEQUAL, gl.GEQUAL oder gl.ALWAYS. Verglichen wird in der Form (ref & mask) OP (stencil & mask). gl.LESS bedeutet also: Der Test besteht, wenn der Referenzwert kleiner ist als der gespeicherte Wert. |
| $ref Pflicht | GLint | 0 | Referenzwert für den Vergleich. Er wird auf den Bereich 0 bis 2n−1 begrenzt, wobei n die Anzahl der Stencil-Bits ist (meist 8). |
| $mask Pflicht | GLuint | 0xFFFFFFFF (alle Bits gesetzt) | Bitmaske, die vor dem Vergleich per UND auf ref und auf den gespeicherten Stencil-Wert angewendet wird. Häufig ist das 0xFF. |
Rückgabewert
undefined).Beispiele
Kontext mit Stencil-Puffer anlegen und Test aktivieren
const canvas = document.querySelector('canvas');
// Ohne stencil: true gibt es meist keinen Stencil-Puffer
const gl = canvas.getContext('webgl', { stencil: true });
console.log('Stencil-Bits:', gl.getParameter(gl.STENCIL_BITS));
gl.enable(gl.STENCIL_TEST);
gl.clearStencil(0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
// Jedes Fragment besteht den Test
gl.stencilFunc(gl.ALWAYS, 1, 0xFF);
console.log(gl.getParameter(gl.STENCIL_FUNC) === gl.ALWAYS);
console.log(gl.getParameter(gl.STENCIL_REF));
Maske zeichnen, danach nur innerhalb der Maske rendern
// Voraussetzung: gl mit { stencil: true }, drawCircle() und drawScene() sind eigene Zeichenfunktionen
gl.enable(gl.STENCIL_TEST);
gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
// Durchgang 1: Kreis nur in den Stencil-Puffer schreiben (Wert 1)
gl.colorMask(false, false, false, false);
gl.stencilFunc(gl.ALWAYS, 1, 0xFF);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
gl.stencilMask(0xFF);
drawCircle();
// Durchgang 2: Szene nur dort zeichnen, wo der Stencil-Wert 1 ist
gl.colorMask(true, true, true, true);
gl.stencilFunc(gl.EQUAL, 1, 0xFF);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
gl.stencilMask(0x00); // Puffer nicht mehr verändern
drawScene();
Umriss um ein ausgewähltes Objekt
// Objekt normal zeichnen und seine Fläche mit 1 markieren
gl.stencilFunc(gl.ALWAYS, 1, 0xFF);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
gl.stencilMask(0xFF);
drawObject(1.0);
// Leicht vergrößerte Version nur außerhalb der markierten Fläche zeichnen
gl.stencilFunc(gl.NOTEQUAL, 1, 0xFF);
gl.stencilMask(0x00);
gl.disable(gl.DEPTH_TEST);
drawObjectOutline(1.05); // einfarbiger Shader
gl.enable(gl.DEPTH_TEST);
gl.stencilMask(0xFF);
// Wichtig · Fallstricke
- Kein Stencil-Puffer: Standardmäßig ist
stencilin den Kontext-Attributenfalse. Dann hatstencilFunc()keine sichtbare Wirkung. Prüfen Sie das mitgl.getContextAttributes().stencilodergl.getParameter(gl.STENCIL_BITS). - Der Test läuft nur, wenn
gl.STENCIL_TESTaktiviert ist. Die Einstellungen bleiben aber auch ohne aktivierten Test gespeichert. - Reihenfolge beim Vergleich: Links steht der Referenzwert.
gl.LESSheißt alsoref < stencilund nicht umgekehrt. Das wird oft verwechselt. - Ein ungültiger Wert für
funclöst den Fehlergl.INVALID_ENUMaus. Abfragen können Sie ihn mitgl.getError(). - In WebGL müssen die Stencil-Einstellungen (
ref,mask,writemask) für Vorder- und Rückseite übereinstimmen. Sonst meldet ein ZeichenaufrufINVALID_OPERATION. Das ist vor allem beistencilFuncSeparate()wichtig. - Die aktuellen Werte fragen Sie mit
getParameter()ab:STENCIL_FUNC,STENCIL_REF,STENCIL_VALUE_MASKsowie dieSTENCIL_BACK_*-Gegenstücke. - In
WebGL2RenderingContextgibt es die Methode ebenfalls. Alle modernen Browser unterstützen sie.