Cinder-SdfText: Initial Release (WIP)

As promised, here is a fully revised shader for the text. It renders the text with the highest quality, even at very small scales. It also performs well when the text is rotated. Speaking about performance: it’s not a cheap shader, but I think it’s worth it.

vec2 safeNormalize( in vec2 v )
{
   float len = length( v );
   len = ( len > 0.0 ) ? 1.0 / len : 0.0;
   return v * len;
}

void main(void)
{
    // Convert normalized texcoords to absolute texcoords.
    vec2 uv = TexCoord * textureSize( uTex0, 0 );
    // Calculate derivates
    vec2 Jdx = dFdx( uv );
    vec2 Jdy = dFdy( uv );
    // Sample SDF texture (3 channels).
    vec3 sample = texture( uTex0, TexCoord ).rgb;
    // calculate signed distance (in texels).
    float sigDist = median( sample.r, sample.g, sample.b ) - 0.5;
    // For proper anti-aliasing, we need to calculate signed distance in pixels. We do this using derivatives.
    vec2 gradDist = safeNormalize( vec2( dFdx( sigDist ), dFdy( sigDist ) ) );
    vec2 grad = vec2( gradDist.x * Jdx.x + gradDist.y * Jdy.x, gradDist.x * Jdx.y + gradDist.y * Jdy.y );
    // Apply anti-aliasing.
    const float kThickness = 0.125;
    const float kNormalization = kThickness * 0.5 * sqrt( 2.0 );
    float afwidth = min( kNormalization * length( grad ), 0.5 );
    float opacity = smoothstep( 0.0 - afwidth, 0.0 + afwidth, sigDist );
    // Apply pre-multiplied alpha with gamma correction.
    Color.a = pow( uFgColor.a * opacity, 1.0 / 2.2 );
    Color.rgb = uFgColor.rgb * Color.a;
}

As you can see, I also chose to use pre-multiplied alpha and got rid of the background color.

-Paul

1 Like