Sub-pixel Antialiasing

EAText supports sub-pixel text antialiasing via FreeType's LCD subpixel hinting. Using it is the same as using other kinds of fonts, though implementing it typically requires a fragment shader that has support for it. Microsoft has patented parts of this under the name of ClearType, and so when we refer to ClearType below, we are referring to Microsoft's implementation of sub-pixel anti-aliasing. We will henceforth abbreviate sub-pixel antialiasing as SubPixelAA.

Enabling

You need to enable this option in FreeType via defining FT_CONFIG_OPTION_SUBPIXEL_RENDERING in ftoption.h or globally. However, beware that this functionality is partially patented by Microsoft until the year 2019 via ClearType, and you must officially license it from Microsoft to use it. As of this writing we are negotiating with Microsoft on this.

EAText enables SubPixelAA via the kOptionSubPixelAA option. You can set this option on individual OutlineFont objects via (e.g.) Font::SetOption(kOptionSubPixelAA, kSCT_LCD_H_RGB) and you can enable it by default for FontServer-created fonts via FontServer::SetOption(kOptionSubPixelAA, kSCT_LCD_H_RGB). If you enable kOptionSubPixelAA then the enabled Outline Font will automatically generate glyphs that are 24 bit RGB encoded as per the documentation for the type. It's up to the graphics engine to convert those to a glyph cache texture entry, though EAText has some default converters.

SubPixelAA support is specific to the type of screen being used, as it depends on the design of the pixels on the screen. This creates some potential runtime problems for executing applications which might have to determine what kind of screen is available.

/// ScreenColorType
/// Specifies how color pixels are implemented on the screen.
enum ScreenColorType
{
    kSCT_Unknown,   /// Display is known to not be LCD, for example.
    kSCT_LCD_H_RGB, /// Horizontal R, G, B. Most desktop LCD displays are like this.
    kSCT_LCD_H_BGR, /// Horizontal B, G, R. A desktop display rotated 180 degrees would be like this.
    kSCT_LCD_V_RGB, /// Vertical R, B, B. Desktop LCD displays rotated 90 degrees clockwise would be like this.
    kSCT_LCD_V_BGR, /// Vertical R, B, B. Desktop LCD displays rotated 90 degrees counter-clockwise would be like this.
    kSCT_LCD_Other  /// Display is LCD but not a linear color type (e.g. PenTile).
};

A shader is required which handles glyph textures with SubPixelAA support. Typically this is something specific to each graphics engine. You may also need to supply glyph cache support for three channel textures. We discuss this more specifically below.

Licensing

We are currently (February 2014) working towards understanding the licensing requirements for ClearType. If you need to know more then talk to the EA legal team via the Legal IP Team @ EAHQ mailing list. However, it's important to be sure that you don't publish any software that uses SubPixelAA until you are sure that IP (intellectual property) issues are resolved.

How SubPixelAA works

SubPixelAA is a form of anti-aliasing that works at the sub-pixel level. It works by using the individual red, green, and blue components of an LCD screen pixel as if they were independent pixels. Consider that an LCD screen when viewed very magnified looks somewhat like this:

When glyphs are drawn with SubPixelAA, they are drawn with variable amounts of coloring in each pixel component:

The following demonstrates size 14 Arial drawn with SubPixelAA, with regular anti-aliasing, and without anti-aliasing. On most LCD monitors the top row (SubPixelAA) will look the smoothest, but it may also show coloring around the edges of the glyphs. The larger the text, the less it needs SubPixelAA, and very large text (>= size 80) may not need any anti-aliasing at all.

The picture below consists of the same text drawn at Arial size 9. The top row is the smoothest of the three and is evenly weighted, but it clearly shows a discoloring that makes it look like the text is not black. The second row is fairly smooth but demonstrates how anti-aliasing has problems with very small text, as the font size is too small for anti-aliasing to look good with some of the letters (e.g. w, s, k). The third row looks very crisp, though slightly blocky. The reason it looks so crisp is that this font (Microsoft Arial) has extensive hinting (desribed in the next section) built into it. The bottom row has no no anti-aliasing nor hinting and looks the worst. It is unacceptable for commercial applications and demonstrates why hinting is so important for smaller sized fonts.

  ClearType
  Anti-Aliasing
  Hinting
  No hinting or anti-aliasing

The http://en.wikipedia.org/wiki/Subpixel_rendering page has more information about this.

Applicability

SubPixelAA as implemented by EAText through FreeType supports computer displays that have horizontally consecutive RGB sub-pixels. Nearly all consumer LCD computer monitors are like this. Some televisions are like this, but not all. Phone and Tablet displays often don't have this kind of screen pixel arragement and often have things like PenTile displays.


PenTile display

When an LCD screen is rotated 90 degrees (as some displays support), the horizontal orientation becomes vertical and the anti-aliasing

SubPixelAA is supported under EAText with TrueType and related outline font types (e.g. .ttf, .ttc, .otf). EAText Effects do not currently support sub-pixel anti-aliasing, though that may be an option in the future. Some TrueType fonts work better than others, but most yield decent results. If you create a font with an effect then SubPixelAA will be disabled. Bitmap fonts (e.g. EATextBmpFont) don't explicitly support SubPixelAA but a 24 bit bitmapped font could be constructed that's pre-built with SubPixelAA encoding. If you are interested in doing this then let us know.

Experimentation

In order to test sub-pixel anti-aliasing we provide the FreeType ftview.exe applet, which lets you experiment with glyph drawing parameters directly out of FreeType. This applet is in the EAText tools directory and runs on Windows 32 and 64 bit platforms. Use F1 at runtime to see a list of options to control the settings. The controls in this app directly correspond to FreeType-level options, which are mostly exposed by EAText by EAText-level options.

Television Behavior

SubPixelAA works on many televisions but doesn't work quite as well as it does on desktop monitors. There are a number of factors here:

Our tests have shown that SubPixelAA on modern LCD/Plasma televisions doesn't look much sharper, but does have better and more consistent glyph weighting.

Glyph Cache

When SubPixelAA is enabled, the EAText OutlineFont::RenderGlyphBitmap function generates a bitmap which is an opacity map like with regular AA glyphs, but is three times as wide (24bpp instead of 8bpp) and and with three times the detail. For example, here's a memory view of the "1" glyph with regular 8bpp opacity:

Here's the same 1 glyph drawn with SubPixelAA 24bpp opacity:

This needs to be directly converted into an RGB texture in the glyph cache. Each RGB triplet above maps to one texel in the texture, and as usual each texel in the texure maps to a pixel on the screen 1:1. While there are 24 bits of information above for each texel, you could conceivably reduce that to 16 bit (e.g. 565) to save space. The opacity of the texel would be calculated by the fragment shader and is typically the average of the three values, though a more advanced algorithm could yield improved results.

Shader

The freetype-gl project has an example vertex and fragment OpenGL shader that is applicable to EAText-based SubPixelAA.

The vertex shader is straightforward:

uniform sampler2D texture;
uniform vec3      pixel;
uniform mat4      model;
uniform mat4      view;
uniform mat4      projection;

attribute vec3  vertex;
attribute vec4  color;
attribute vec2  tex_coord;
attribute float agamma;
varying   float vgamma;
 
void main()
{
    vgamma = agamma;
    gl_FrontColor = color;
    gl_TexCoord[0].xy = tex_coord.xy;
    gl_Position = projection*(view*(model*vec4(vertex,1.0)));
}

The fragment shader is a little more involved. The following is similar to the shader that freetype-gl uses, though we are looking into coming up with something better because the shader below seems to not have as much AA effect as it should.

uniform sampler2D texture;
uniform vec3      pixel;
varying float     vgamma;

void main()
{
    vec2 uv = gl_TexCoord[0].xy;

    if(pixel.z == 1.0) // If there is just 1 byte per pixel...
    {
        float a = texture2D(texture, uv).r;
        gl_FragColor = gl_Color * pow(a, 1.0/vgamma);
    }
    else // Else do SubPixelAA. 
    {
        vec4 current  = texture2D(texture, uv);
        vec4 previous = texture2D(texture, uv+vec2(-1.,0.)*pixel.xy);
  
        current = pow(current,  vec4(1.0/vgamma));
        previous= pow(previous, vec4(1.0/vgamma));
  
        float r = current.r;
        float g = current.g;
        float b = current.b;
  
        float t      = max(max(r,g),b);
        vec4 color   = vec4(gl_Color.rgb, (r+g+b)/3.0);
        color        = t*color + (1.0-t)*vec4(r,g,b, min(min(r,g),b));
        gl_FragColor = vec4(color.rgb, gl_Color.a*color.a);
    }
}

Sub-pixel positioning

In addition to the topic of sub-pixel antialiasing there is the concept of sub-pixel positioning. In that case glyphs are placed on fractional pixel positions along the text baseline. There are three primary ways of accomplishing this graphically:

  1. Layout the glyphs with fractional positions and advances, but at the actual step of drawing glyphs, round their positions to pixel boundaries. This results in lines of text that have accurate width, but individual glyphs may look horizontally slightly misaligned.
  2. Layout the glyphs with fractional position and advances, and make/draw special versions of each glyph whereby each version has specialized antialiasing for that position. This results in accurate line width and good looking glyphs, but explodes the size of your glyph cache because you need to cache multiple glyphs, one for each fraction.
  3. Layout the glyphs with fractional position and advances, and make anti-aliased versions of glyphs (better if using SubPixelAA), but have the fragment shader revise the channel calculation to shift the glyph. This results in accurate line width and glyphs that look almost as good as case #2 above for many cases, and yet doesn't have the downside of requiring multiple glyph caching. The freetype-gl package's text.frag file shows how to implement this as a variation of the fragment shader shown above.

Links


End of document