SDF Text Clipping

Hi,

nice to hear you’re having fun with SDF text. Note that I have since abandoned that specific kind of SDF text rendering in favour of multi-channel SDF’s. @chaoticbob created a cool Cinder Block for it, to which I contributed a much improved shader. If you find that you need even crispier text, have a look.

With that being said, let’s turn to the issue at hand. You may want to look into using the stencil buffer. This allows you to mask portions of your canvas. The upside is that this also works for non-rectangular areas and you don’t need to render to an Fbo, so your text stays crisp no matter what. The downside is that it is a boolean test, so it will be impossible to use an anti-aliased mask. This can be remedied using a post-process like FXAA or SMAA, but I’ll not go into that in this post.

By default, the stencil buffer is disabled for performance and memory reasons. Enable it using:

CINDER_APP( YourApp, RendererGl( RendererGl::Options().stencil() ) )

Then, before drawing your text, render a mask to the stencil buffer. This is as simple as setting up OpenGL to render to the stencil buffer, then rendering the shape you want:

// Disable color and depth buffers.
gl::colorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
gl::depthMask( GL_FALSE );

// Prepare stencil buffer.
auto ctx = gl::context();
ctx->pushBoolState( GL_STENCIL_TEST, GL_TRUE );
ctx->pushStencilFunc( GL_ALWAYS, 1, 0xFF );
ctx->pushStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
ctx->pushStencilMask( 0xFF );

gl::clear( GL_STENCIL_BUFFER_BIT );

// Now render your shape using polygons. No need to
// use a fragment shader, unless you want to do something
// fancy like `discard`-ing some pixels.

Next, setup OpenGL to render normally while enabling the stencil mask:

// Enable color and depth buffers.
gl::depthMask( GL_TRUE );
gl::colorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );

// Enable stencil testing.
gl::stencilFunc( GL_EQUAL, 1, 0xFF );
gl::stencilMask( 0x00 );

// Render your text like you normally would.

Finally, restore the OpenGL state to no longer use the mask:

// Restore stencil buffer.
ctx->popStencilMask();
ctx->popStencilOp();
ctx->popStencilFunc();
ctx->popBoolState( GL_STENCIL_TEST );

-Paul

1 Like