«

»

Aug
12
2007

XNA Vector Font Renderer

I’ve been fiddling around with font rendering again this weekend. For my upcoming game, I wanted a cool intro effect like in some movies, where the displayed text is very very slowly expanding. But I couldn’t quite replicate that effect with the XNA SpriteFont class. Even with antialiasing turned on, the borders of the text were flickering. Using very large font sizes resulted in hopelessly oversized .xnb files with only a slight improvement for the unsteady borders.

So my new solution was to write a component that renders vector-based text instead of bitmaps. Extracting the vector data from a font was a bit harder than I had expected because fonts consist mostly of complicated second and third order bezier curves. I managed to break these down into plain straight line segments and am now in the possession of a content pipeline importer that converts .ttf fonts into arrays of line segments. Behold:

Screenshot of vector fonts rendered as outlines in 3D

In the upper left is my replacement sprite font importer which can take the place of Microsoft’s own importer by the flip of a combobox. It produces identical .xnb files that can be used with the SpriteFont class, so you can toggle forth and back at will. The upper line is from a font imported with my own importer (using FreeType) and the lower line is from the same font imported with the XNA SpriteFont importer (using Windows Vista .ttf rendering).

The big outlined vector text highlights the separate outlines the characters consist of in the upper line and shows the normal rendered result below. Both outputs have been generated by writing a series of line strips into a vertex buffer and rendering it.

Now filling the characters requires the outlines to be tessellated into a triangle mesh, which is another unexpected complexity I hadn’t thought about when I set out to create a vector font rendering component. But I already took the hurdle by cheating with OpenGL’s gluTess...() routines. Of course, these will only be used in the content pipeline assembly, the final game .exe has zero references to unmanaged code and/or OpenGL.

Update: I completed the GLU tessellator interfacing code and am now proud to announce the near completion of the Nuclex.Fonts VectorFont importer. Once I’m done with the runtime side of things, you can have smooth-zooming text without any blurry pixels or loss of quality, rotating 3D text or just a means of converting strings into vertices for whatever purpose you want.

Screenshot of vector fonts rendered as 3D faces in wireframe mode

4 comments

  1. Huminaboz says:

    How did it go?

  2. Cygon says:

    I’ve completed this and it’s a finished library for 3D text rendering now. It can generate outlines, flat text (like in the last image) and even extruded text. The rendering side is done in XNA, but the vector data extraction and tessellation code is plain C++.

    If you’re asking because you’re interested in the code, it’s open sourced and can be viewed here:
    https://devel.nuclex.org/framework/browser/graphics/fonts/Nuclex.Fonts.Content.TrueTypeImporter/trunk

  3. Oleg Skripnyak says:

    Have almost the same issue.
    Just want to convert .ttf to the same format as GetGlyphOutline does by the TTFProcessor, ie without C++, but DllImport

  4. Cygon says:

    Is TTFProcessor some class in Microsoft’s own content pipeline font processor for XNA?

    I can’t help you much with GetGlyphOutline() since I built mine on FreeType (advantages: far better quality, portable, nicer API) and FT_Outline_Decompose(). There’s a .NET binding for FreeType as well, Tao.FreeType.

    Otherwise, what is your issue? You say you have "almost the same issue" – but don’t mention any issue.
    GetGlyphOutline() can easily be called via P/Invoke (DllImport), its signature is probably already on pinvoke.net.

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Please copy the string HNgGul to the field below:

Social Widgets powered by AB-WebLog.com.