Improved Text Quality in WebGL

I am looking for a method to get better quality (arbitrary) text inside WebGL. I am currently using bitmap rendering on a two-dimensional canvas and blitting them in a WebGL context.

This method is described here http://delphic.me.uk/webgltext.html

This is the only solution for drawing arbitrary unicode text inside WebGL that I know about right now. The problem with this method is that they are bitmap fonts and appear blocky with smaller font sizes. I mainly use font size 18, and the result is pretty blocky compared to desktop fonts.

I know that threeJS has a font library that generates improved text, but I don't want to use threeJS, because I have my own shell that works fine for what I need, and I don't want to add the extra overhead of threeJS.

So how do you create better text in WebGL? Are there any methods to extract text shapes in Javascript to improve quality?

+15
javascript html5 opengl-es webgl true-type-fonts
source share
3 answers

Having worked with fonts for some time, I see 6 ways to make fonts in WebGL, all with advantages and disadvantages:


Font like geometry

  1. Get an open source font like Google does ( Open Sans and Roboto are very popular)
  2. Read font curves using OpenType or similar ( https://nodebox.imtqy.com/opentype.js/ )
  3. Triangulate character curves. My favorite for this is Earcut, as it is very fast https://github.com/mapbox/earcut
  4. Draw polygons for each character like regular WebGL triangles.

advantages

  • Very fast, if you have a lot of text and need full-featured fonts, this is your best bet. Font scaling is performed on the GPU using matrix operations.

disadvantages

  • The quality of the font displayed depends on the anti-aliasing enabled by your WebGL browser. Safari runs 8x8 AA, which looks good, but all other browsers use only 4x4, which may look blocky. In addition, the mobile browser does not include AA at all, which makes fonts very mobile on your mobile devices.

canvas

This is also called Dynamic On-Demand Textures. Display only the text glyphs on the (offscreen) canvas and drag it onto the screen as a WebGL texture, as described here: http://delphic.me.uk/webgltext.html

advantages

  • Decent quality.

disadvantages

  • Speed, depending on how much text you need to render, at what time it can work fine. Especially if you only need to render static text.

Age of Empires III uses this method.


Bitmap Fonts

If you want maximum speed with the best quality for a limited character set and a fixed character size (Game), it's probably best to create your own bitmap containing the characters you want to use and drag them onto the screen as needed. You can find quite a few such bitmaps on the Internet.

This is quick and easy, but restricts the languages ​​and characters that you can use, but you will not mind it, for example, in a game.

Benefits:

  • Just understand
  • It's trivial to create a texture satin
  • You can use color fonts.

disadvantages

  • Looks awfully blurry when zoomed in.
  • You must first render all the glyphs that are used.
  • Requires texture for font size
  • For optimal texture utilization, texture bin packaging is required. example

Signature field fonts

Chris Green of Valve wrote a book on the use of distance fields for textures. You will want to read the 2007 SIGGRAPH document, Enhanced Alpha Zoom Testing for Vector Textures and Special Effects.

Typically, a font texture atlas is as follows . The texture of the SDF looks like this . Yes, the texture satin SDF looks blurry when displayed “as is”. This is because the 8-bit channel was encoded as:

  • 0 → -1.0 (outside)
  • 255 → +1.0 (inside)

Benefits:

  • You can use one texture to scale fonts from very small (6 pixels) to very large (200 px +) without loss of quality,
  • Smoothing is often "free."

Disadvantages:

  • You must first render all the glyphs used,
  • SDF texture preprocessing is usually performed offline due to SLOW preprocessing (~ 15 seconds),
  • Not many people understand how to create quality smoothing. Hacks such as smoothstep() and fwidth() give poor quality results due to people interpolating texture space instead of screen space. It also doesn't help that WebGL fwidth() uses the wrong constant.
  • The single-channel SDF does not save edges, as Valve hints in his article. Their solution was to use multi-channel SDF, but did not provide any details. See Master's thesis by Viktor Hlumsky or its open source code.
  • A “cell fill” or border of a few pixels is required if the SDF fonts are used in small sizes.
  • Only monochrome fonts supported

Nevertheless, if you have several fonts, then SDF fonts can be a huge gain both in size (only 1 is needed) and in quality (it looks fantastic for both small and large sizes)

How to create SDF textures

Now there is an easy-to-use npm module that generates the SDF textures and metadata available here .


SDF Demos


GPU Fonts

People study the storage of cubic curves on the GPU and completely bypass the texture using an intelligent fragment shader that does all the hard work of rendering.

This blog has a summary of font rendering as of February 2017.

advantages

  • High quality glyphs in normal and large sizes

disadvantages

  • High cost and complexity of shaders
  • Has quality problems with small sizes

GPU font demonstration


Canvas overlay

For my current project, I use an HTML5 2D canvas to render text and other 2D primitives and overlay it using transparency on top of the WebgGL canvas. I was surprised at the speed obtained, it surpasses all other methods described here in speed and quality very well.

As long as your text is static 2D and you don't need any 3D transforms, I would recommend this. In my project, this is about 2 times faster than in the previous method (Font as Geometry).

+31
source share

Looking at the source code for three.js, you can find a solution.

Here is the code to create the three.js font https://github.com/mrdoob/three.js/blob/master/src/extras/FontUtils.js

He speaks at the top

  * For Text operations in three.js (See TextGeometry) * * It uses techniques used in: * * typeface.js and canvastext * For converting fonts and rendering with javascript * http://typeface.neocracy.org * * Triangulation ported from AS3 * Simple Polygon Triangulation * http://actionsnippet.com/?p=1462 * * A Method to triangulate shapes with holes * http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/ 

Typeface.js provides font data as well as an online form for converting TrueType fonts .

Other solutions:

+3
source share

Pixi.js agrees with the recommendation above for SDF.

https://github.com/PixelsCommander/pixi-sdf-text

They say (and they are a great browser game project)

SDF is the most efficient way to draw text in WebGL. It uses a special kind of raster atlases and GLSL shaders to draw vector-scalable text very clearly on the GPU.

And that was from MapBox, which at least did it at some point too.

0
source share

All Articles