Draw Text as 3D Objects with OpenGL

From Qt Wiki
Revision as of 15:22, 14 January 2015 by Maintenance script (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Draw Text as 3D objects with OpenGL

There are a couple of functions in WGL (Windows Graphics Library [msdn.microsoft.com]).aspx) which can be used to draw text as nice 3D objects in OpenGL. There is a well known example at NeHe [nehe.gamedev.net]. However, this is not portable at all, and since I’m using Qt anyway, I was looking for a way to have this done with Qt. I was surprised that there was no such function already available within Qt, but then I stumbled across this example on Stackexchange [stackoverflow.com] that got me started.

Before I get to the code, some drawbacks of this example:

  • It uses the fixed-function pipeline. (GL_QUAD_STRIP’s and DisplayLists). Im sure this can be done in a “more modern” way with VBO’s, but my OpenGL knowlegde is not yet at that level.
  • it relies on GLU for polygon tesselation. There might be better alternatives around or even some within Qt.
  • No real character set (or even UTF) handling. It only uses the first 256 characters.
  • side effects on the matrix.

The example uses QFont to get the font outline for each character (glyph). The basic idea is to create two flat outline-polygons for the front- and back-“plane” of a glyph and then create the “wrapping” in between the front- and backplane. Although it seems more difficult at first, it was pretty easy to create the wrapping in between the two outline-polygons with GL_QUAD_STRIP. The tricky bit was the polygon tesselation of the glyph outline, because the glyph-polygons are not concave and may have one or more holes. I’m using the polygon tesselation facility available in GLU.

The text3d class can be subclassed by a GLWidget or GLWindow object. There are only 2 functions required to draw text: initfont() and print(). The initialization of the font cannot easily be done in the constructor, because the contest is probably not initialized during construction. Therefore the initfont().


The implementation file: text3d.cpp

The initialization just loops through the first 256 char’s and calls buildglyph() for each of them.
The print() function uses glCallLists() to “interpret” a complete string. See below how the char-by-char advance works.
At the beginning we need to set up both, the tesselation and the display list.
Now it’s ready to tesselate the “front plate” polygon.
Do the whole tesselation a second time with an offset applied for the “back plate”. The “offset” (thickness) is set in
The “wrapping” between the two “plates” is simple compared to the tesselation.
This is where the char-by-char advance is done. Get the width from the font metrics and apply a glTranslate() with that value. This goes into the displaylist as well. (This may have side-effects as the matrix is not in the same “state” as before the call!!!)
The whole thing can actually be used in a init() and render() functions within a OpenGL object like this:


I’ve found another example here [yycking.blogspot.ch] that tries to do the same thing. Although completely in chinese, it looks more Qt’ish to me. But I’m not that much of an expert on Qt either.