8
\$\begingroup\$

I'm using FTGL library to render fonts in my game, but I have completely no idea how to create an outline around text. Achieving a shadow could be easy, because I can simply do it like this:

(pseudo code)

font.render(Color::BLACK, position.x + 1, position.y + 1); // Shadow
font.render(Color::WHITE, position.x, position.y)          // Normal text

But how to create an outline? Unfortunately I haven't found any interesting solutions for it over internet which seemed to me a bit strange, because I thought it's quite popular problem.

Drawing outline with just a bigger font is not a right way, because as I found out, letters just don't match in this case:

enter image description here

So is there any simple way to create an outline for fonts? How do they do it in real games?

Thanks in advance for any answer

\$\endgroup\$
3
  • 1
    \$\begingroup\$ A dirty solution could be to render to a texture the same text, and then render this texture scaled up x1.2, for example. \$\endgroup\$
    – Dan
    Commented Dec 30, 2012 at 12:27
  • 2
    \$\begingroup\$ @Dan That will lead to exactly what he has shown in his image above. Even rendering one letter at a time in this way, would lead to problems, since the outer outlines would be thicker than the inner ones (which might be non-existent). \$\endgroup\$
    – Engineer
    Commented Dec 30, 2012 at 14:23
  • 1
    \$\begingroup\$ What type of font are you using? FTGL supports Outline fonts out of the box for Vector fonts. OpenGL line width can be used to control thickness. \$\endgroup\$
    – Paul-Jan
    Commented Dec 30, 2012 at 15:39

3 Answers 3

7
\$\begingroup\$

Flexible & Accurate: Filters

Use a texel filter either on the texture on the CPU side, or if you are using programmable pipeline OpenGL, directly in the fragment shader.

The idea of a filter is simply that you run through a 2D loop to process every texel. If it is white, then you run through an inner 2D loop for each of its surrounding pixels in some radius, and adapt accordingly. This is also known as a box filter, though if you include the radius check, it is really a circular filter -- which avoids axis-al artifacting.

A faster way to do this is to precalculate the set of offsets from each central pixel that you check; this way, you needn't run a square root for every pixel surrounding a given pixel. You want to keep complexity down to `O(texWidth*texHeight) rather than O(texWidth*texHeight*filterRadius*filterRadius), in other words.

Easy: Multiple renders

Another way to achieve the effect would be not to scale the text, but instead to render your red outline at each of eight (or more) directions, each slightly offset from the original in that direction:

 \|/
--+--
 /|\

By offsetting each of the red versions like this, you would get a fairly uniform outer edge around your original text. Bear in mind that when shifting diagonally, you should use the same vector magnitude as when you shift horizontally or vertically, rather than simply offsetting by the same x and y values (which leads to a approximatlely 1.4x further length -- basic trig).

FYI

This sort of effect is known as dilation, and is sometimes performed via Minkowski Summation, which is the vector-based (continuous) approach to the pixel-based (quantised) box filter I described above.

\$\endgroup\$
6
\$\begingroup\$

This feature is implemented directly in FTGL but it is only available in the ExtrudeFont class. You simply define an outset for the font:

font = new FTExtrudeFont(...);
font->FaceSize(80);
font->Depth(0);
font->Outset(0, 5);

Then you can use a different colour for the two render modes:

glColor3f(1.0, 1.0, 1.0); /* White inside */
font->Render("Hello", FTPoint(), FTPoint(), FTGL::RENDER_FRONT);
glColor3f(1.0, 0.0, 0.0); /* Red outline */
font->Render("Hello", FTPoint(), FTPoint(), FTGL::RENDER_SIDE);

Here is the result, with antialiasing toggled off and on:

Resulting image

\$\endgroup\$
1
  • \$\begingroup\$ Thank you Sam! That's really what I wanted to hear - that FTGL actually has something like this. Thanks once again. \$\endgroup\$ Commented Dec 31, 2012 at 9:09
2
\$\begingroup\$

Not related to FTGL but there's a great article from Valve about glyph rendering. It provides high quality rendering with small memory requirement, and effects like outlines or shadows can be simply implemented.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Worth warning the OP that this approach requires an understanding of the programmable GPU pipeline, i.e. shaders. \$\endgroup\$
    – Engineer
    Commented Dec 30, 2012 at 15:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .