Signatur
Beschreibung
stencilOpSeparate() bestimmt, was mit dem Wert im Stencil-Puffer geschieht, nachdem ein Fragment den Stencil-Test und den Tiefentest durchlaufen hat. Anders als stencilOp(), das immer für beide Seiten gilt, kann man hier über den Parameter face gezielt nur Vorderseiten (gl.FRONT), nur Rückseiten (gl.BACK) oder beide (gl.FRONT_AND_BACK) ansprechen.
Gebraucht wird das vor allem bei Techniken, bei denen Vorder- und Rückseiten eines Objekts den Stencil-Puffer unterschiedlich verändern sollen. Das bekannteste Beispiel sind Stencil-Schattenvolumen (z-pass/z-fail): Rückseiten erhöhen den Zähler, Vorderseiten verringern ihn. Mit stencilOpSeparate() geht das in einem einzigen Zeichendurchgang, statt das Volumen zweimal mit unterschiedlichem Culling zeichnen zu müssen.
Die drei Aktionen gelten für drei Fälle: fail, wenn der Stencil-Test fehlschlägt; zfail, wenn der Stencil-Test besteht, der Tiefentest aber fehlschlägt; zpass, wenn beide bestehen (oder kein Tiefentest aktiv ist). Wirksam wird das Ganze nur, wenn gl.enable(gl.STENCIL_TEST) gesetzt ist und der Zeichenpuffer tatsächlich einen Stencil-Puffer besitzt.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $face Pflicht | GLenum | Welche Seiten betroffen sind: gl.FRONT, gl.BACK oder gl.FRONT_AND_BACK. |
|
| $fail Pflicht | GLenum | gl.KEEP | Aktion, wenn der Stencil-Test fehlschlägt. Erlaubt: gl.KEEP, gl.ZERO, gl.REPLACE, gl.INCR, gl.INCR_WRAP, gl.DECR, gl.DECR_WRAP, gl.INVERT. |
| $zfail Pflicht | GLenum | gl.KEEP | Aktion, wenn der Stencil-Test besteht, der Tiefentest aber fehlschlägt. Gleiche Werte wie bei fail. |
| $zpass Pflicht | GLenum | gl.KEEP | Aktion, wenn Stencil- und Tiefentest bestehen oder kein Tiefentest aktiv ist. Gleiche Werte wie bei fail. |
Beispiele
Grundlegender Aufruf und Abfrage des Zustands
const canvas = document.createElement('canvas');
// Stencil-Puffer muss explizit angefordert werden
const gl = canvas.getContext('webgl', { stencil: true });
gl.enable(gl.STENCIL_TEST);
// Nur Vorderseiten: bei bestandenem Test Referenzwert schreiben
gl.stencilOpSeparate(gl.FRONT, gl.KEEP, gl.KEEP, gl.REPLACE);
console.log(gl.getParameter(gl.STENCIL_PASS_DEPTH_PASS) === gl.REPLACE);
console.log(gl.getParameter(gl.STENCIL_BACK_PASS_DEPTH_PASS) === gl.KEEP);
Schattenvolumen (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.depthMask(false); // Tiefe nicht verändern
gl.colorMask(false, false, false, false);
gl.stencilFunc(gl.ALWAYS, 0, 0xff);
// Rückseiten hinter der Geometrie: +1, Vorderseiten: -1
gl.stencilOpSeparate(gl.BACK, gl.KEEP, gl.INCR_WRAP, gl.KEEP);
gl.stencilOpSeparate(gl.FRONT, gl.KEEP, gl.DECR_WRAP, gl.KEEP);
drawVolume();
// Zustand zurücksetzen
gl.colorMask(true, true, true, true);
gl.depthMask(true);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
};
Beide Seiten gleichzeitig setzen
const gl = document.querySelector('canvas').getContext('webgl2', { stencil: true });
gl.enable(gl.STENCIL_TEST);
gl.clearStencil(0);
gl.clear(gl.STENCIL_BUFFER_BIT);
// Entspricht gl.stencilOp(gl.KEEP, gl.KEEP, gl.INVERT)
gl.stencilOpSeparate(gl.FRONT_AND_BACK, gl.KEEP, gl.KEEP, gl.INVERT);
console.log(gl.getError() === gl.NO_ERROR);
// Wichtig · Fallstricke
- Kein Stencil-Puffer, keine Wirkung: Standardmäßig ist
stencil: false. Fordere den Kontext mitgetContext('webgl', { stencil: true })an und prüfe mitgl.getContextAttributes().stencil, ob er wirklich vorhanden ist. - Ohne
gl.enable(gl.STENCIL_TEST)werden die Aktionen ignoriert. - Ungültige Enum-Werte lösen
gl.INVALID_ENUMaus, prüfbar mitgl.getError(). - Was als Vorderseite gilt, hängt von
gl.frontFace()ab (Standard:gl.CCW). Auf Punkte und Linien werden immer die Vorderseiten-Einstellungen angewendet. INCR/DECRbleiben an den Grenzen 0 bzw. 2n−1 stehen,INCR_WRAP/DECR_WRAPlaufen über. Für Schattenvolumen nimmt man die Wrap-Varianten.- In WebGL 1 müssen die Masken und Referenzwerte von Vorder- und Rückseite (
stencilFuncSeparate,stencilMaskSeparate) übereinstimmen, sonst liefern ZeichenaufrufeINVALID_OPERATION. Für die Operationen selbst gilt diese Einschränkung nicht. - Verfügbar in
WebGLRenderingContextundWebGL2RenderingContextin allen modernen Browsern.