StencilGL 2.0

glStencilOpSeparate

glStencilOp with separate actions for front-facing and back-facing triangles.

Signature

void glStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);

How it works

Same three cases as glStencilOp, but only for the faces you name. The classic use is stencil shadow volumes: drawing the volume once with culling off, back faces increment and front faces decrement, so each pixel ends up counting how many volumes it is inside. A pixel with a count other than 0 is in shadow.

It saves drawing the volume twice with glCullFace in between.

fragmentstencil test(ref & mask) func (stored & mask)depth testdrawndppassdiscardedsfaildiscardeddpfailpasspassfailfailglStencilFuncglDepthFuncglStencilOp(sfail, dpfail, dppass)
Every fragment meets the stencil test first, then the depth test. glStencilFunc sets the first test; glStencilOp chooses what is written into the stencil buffer at each of the three exits: sfail, dpfail and dppass. A discarded fragment draws nothing, but its stencil action still runs.

Parameters

faceGLenum

Which faces these actions apply to.

Common values

GL_FRONT
Front-facing triangles (see glFrontFace).
GL_BACK
Back-facing triangles.
GL_FRONT_AND_BACK
Both: the same as glStencilOp.
sfailGLenum

Action when the stencil test fails.

Common values

GL_KEEP
Leave the stored value as it is (default for all three).
GL_REPLACE
Write ref (from glStencilFunc). The usual way to paint a mask.
GL_ZERO
Write 0.
GL_INCR / GL_DECR
Add or subtract 1, stopping at the maximum (255 with 8 bits) or at 0.
GL_INCR_WRAP / GL_DECR_WRAP
Add or subtract 1, wrapping around (255 + 1 = 0). Shadow volumes count with these.
GL_INVERT
Flip every bit of the stored value.
dpfailGLenum

Action when the stencil passes but depth fails.

dppassGLenum

Action when both pass.

Tips & pitfalls

  • Use the _WRAP versions for counting: with plain GL_DECR a count that dips below 0 would stick at 0 and break the sum.

Errors

When the call is invalid it does nothing and sets an error, which glGetError returns:

GL_INVALID_ENUM
face or any action is not an accepted value.

Example

example.cpp
1// z-fail shadow volume: count where the volume hides behind geometry
2glDisable(GL_CULL_FACE);
3glStencilOpSeparate(GL_BACK,  GL_KEEP, GL_INCR_WRAP, GL_KEEP);
4glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR_WRAP, GL_KEEP);
5drawShadowVolumes();
Official Khronos documentation