[World] New font tricks

Daniel Phillips phillips at phunq.net
Sun May 27 21:58:43 PDT 2012


Progress on typeface rendering continues.

Glyphs and text string rendering now uses 3D basis vectors for orientation, 
which gives it the ability not only to render precisely positioned text, but 
also allows general scaling, rotation and 3D orientation. In general, affine 
transformations with perspective are now supported. Font24.png demonstrates 
this.

Basis vectors are pretty cool. To render text standing up on the ground plane 
at one meter per texel, you simply use the X and Z unit vectors as the 
rendering basis.  To render at a more reasonable size, scale down the basis 
vectors to roughly the dimensions of one screen pixel.

Rendering text in 3D orientation is mainly a curiosity. The primary use case 
coming up is screen-aligned, constant size text that tracks some 3D position. 
To do the screen-aligned part, the text is rendered using an orthogonal 
projection mapping the screen pixel per pixel, with the X and Y unit vectors 
as the basis. By telling Freetype to use "dots per inch" of 72, the mapping  
becomes: one point equals one texel equals one pixel. This nice relation helps 
a great deal with both accuracy and sanity, otherwise life in a sea of strange 
typographical units can get frustrating indeed.

Rendering screen-aligned text according to a 3D position is easy. The object 
is to make the text rendered in the orthogonal projection appear as if it were 
rendered as a billboard in the perspective projection. All we need to do is 
transform the 3D world position of the text into screen coordinates using the 
current view and projection matrices, giving the pixel coordinates for the 
lower left text origin.

But we also need to take care of one nasty problem: 3D text must work 
correctly with the depth buffer so that the text properly hides objects behind 
it and is hidden by objects in front of it. Unfortunately, he depth buffer 
mapping for an orthogonal projection and for a perspective rendering are not 
at all the same. We need to render the text in the orthogonal projection at a 
distance that produces exactly the same values in the depth buffer as if we had 
rendered it in the perspective projection. Wow, how on earth do we know what 
that distance should be? At least, the entire text is rendered at the same 
distance from the eye, otherwise I doubt it would even be possible to match 
the depth mapping between the two projections.

Calculating the correct render depth turned out to be awfully hard.I am not a 
great mathematician - far from it - but I try to make up for it in other ways. 
After initially failing to deduce the formula from the OpenGL specification, I 
discovered it by experiment. I created a test bed to display the text at some 
randomly chosen depth, then move my viewpoint forward and back until the text 
ends up hidden by one object and hiding the other. At that point I knew the 
distance from my eye to the object, and that my randomly chosen number was the 
correct value to put into the depth buffer at just that distance. In this way I 
found some specific points on the curve, including the general range that the 
the number should be in. Should it be positive or negative? (Negative) Should 
it be big or small? (Usually small.) Close to zero or one? (Close to one.) 
Varying linearly with the world distance? (No, varying linearly with the 
inverse of the world distance.) Putting those clues together I eventually 
concocted a formula that always translates the perspective depth exactly to 
the correct orthogonal depth. Once I had the formula, it was straightforward 
to go back to the specification and verify that it is in fact the correct 
formula. So that is how I did that, and why I did not get a lot of sleep last 
night.

While I was in there, I added Unicode support for text strings, see 
"font26.png". This phrase means "happiness" in Japanese, using one Kanji and 
two Hirigana characters. Notice how the text nestles itself between the two 
spheres, just as it should. Now you know a little about the kind of effort that 
needs to go into making such a seemingly simple thing work properly.

There are still a few more steps before the new text renderer goes into 
service. I need to implement a platform independent interface to the font 
loader so that nobody needs to specify actual file names for font files. 
Alternatively I could embed a basic font file in the distribution, which is 
allowed legally because these fonts are all covered by Free licenses. But the 
files are not tiny, for example, about 140K for Liberation Sans Regular, which 
will be the basic World Welder system font. And we want to have lots of fonts. 
I might end up embedding one font file in the tarball anyway, but for now I 
will implement the Freetype Cache library interface, so fonts can be specified 
in terms of descriptive terms instead of exact names. This library also 
optimizes repeated access to many fonts from many programs, so startup time 
should be improved by not needing to read the font file from disk as often.

Then I need to ruggedize the code and protect the OpenGL state that the font 
render uses. Finally, the whole good sized piece of code, needs to be 
"promoted" from its testbed into the World Welder runtime library. Phew, a lot 
of work already and still more to do. All in the name of text display that 
doesn't hurt your eyes. That is more than enough reason in my opinion.

Regards,

Daniel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://phunq.net/pipermail/world/attachments/20120527/8178fd6c/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: font24.png
Type: image/png
Size: 106361 bytes
Desc: not available
URL: <http://phunq.net/pipermail/world/attachments/20120527/8178fd6c/attachment-0002.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: font26.png
Type: image/png
Size: 76758 bytes
Desc: not available
URL: <http://phunq.net/pipermail/world/attachments/20120527/8178fd6c/attachment-0003.png>


More information about the World mailing list