Real-time 3D texts

2 minute read

Recently I was given a task of creating real-time 3D texts and I would like to share some ideas on how I approached it. 3D texts are necessary in some specific areas of real-time graphics - such as in game user interfaces, on-air graphics or in various VR / AR applications. It is not particularly complicated to create 3D text these days. However it becomes a bit more tricky when you need some nice bevel around the edges, or if you want to offset shape of the glyphs - by expanding or shrinking them. Such features could be found in some real-time frameworks, but this was not my case and custom implementation of text bevelling and offsetting would be way beyond my skills.

Considering the fact that Houdini already has top-notch SOP tools, I decided to rather keep it simple and use them. Polybevel, Poly Expand 2D and Boolean SOPs were essential for generating desired geometry. Offset of characters could be tweaked heavily without breaking geometry thanks to straight skeleton implementation in Houdini.

I have build simple HDA that produces 3D glyphs and saves each of them on disk in alembic format (along with some data that could be used in real-time applications). These glyphs are then loaded on demand to form texts in real-time. Generating glyphs with new font is a matter of couple minutes. Once generation is complete, loading and displaying them is a matter of milliseconds.

Sometimes it might be desirable to use different shaders for different offset variations. The easiest solution is to generate separate geometry for each offset configuration and then merge them in real-time application - each having its own shader assigned.

When I was working on this HDA, Houdini 18 (featuring new Polybevel with collision detection) was not yet available. Therefore I have created some “fixes” to overcome common issues of geometry intersections when using bevelling. It wasn’t ideal, but it solved majority of problems and eventually worked quite good.

Each glyph is saved by its Unicode code point (integer representing the Unicode glyph) along with json file containing information about width and height of the glyphs. When developing real-time application, one could easily convert desired string to series of Unicode code points (for example using ord() function in Python) and load corresponding alembic file for each glyph. By utilizing width and height values, glyphs could be arranged one next to another (without unnecessary gaps).

In case you are interested in using this HDA, feel free to clone it from this github repository. There is also simple python script to get all available glyphs given font could possibly offer (based on this stackoverflow thread). By generating all of them, you could rest assured that every possible glyph is available in its 3D version.

Following video shows this setup used in Slovak version of show Family Feud (5 proti 5).

Thanks for reading and have fun generating all sorts of 3D texts. :blush:

P.S. I was curious how straight skeleton works and was therefore trying to recreate its simplified implementation in VEX. I am attaching one interesting error I have encountered during my experiments. Mistake in my VEX code somehow produced this nice "glitchy" look.