I am searching a method to draw better quality (arbitrary) text inside WebGL. Currently I am using bitmap font rendering on a 2D canvas and blitting them into the 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 I know of right now. The problem with this method is that these are bitmap fonts and look blocky on smaller font sizes. I mostly use a font size of 18 and the result is quite blocky compared to desktop quality fonts.
I know that threeJS has a font library which generates better looking text, however I do not want to use threeJS as I have my own wrapper which is working fine for what I need and don't want to add the additional overhead of threeJS.
So how to create better quality text in WebGL ? Are there methods to extract text shapes in Javascript to improve quality ?
After working with Fonts for some time, I can see 6 ways to do fonts in WebGL, all with advantages and disadvantages:
This is also called "On Demand Dynamic Textures". Render only the text glyphs to the (offscreen) canvas and blit it to the screen as a WebGL texture, as described here: http://delphic.me.uk/webgltext.html
The game Age of Empires III uses this method.
If you want max speed with best quality for a limited set of characters and a fixed character size (Game), it is probably best to create your own bitmap featuring the characters you want to use and blit them to the screen as needed. You can find quite a few of these character bitmaps predone on the internet.
This is fast and easy, but limits the languages and characters you can use but you would not mind this in a Game for example.
Chris Green of Valve wrote the "book" on using Signed-Distance Fields for textures. You'll want to read the 2007 SIGGRAPH whitepaper "Improved Alpha-Tested Magnification for Vector Textures and Special Effects
Normally a font texture atlas looks like this. A SDF texture looks like. Yes, the SDF texture atlas looks blurry when rendered "as-is". That's because the 8-bit channel has been encoded as:
smoothstep()
and fwidth()
give poor quality scaled results due to people interpolating in texture space instead of screenspace. It also doesn't help that WebGL's fwidth()
uses the wrong constant.That all said, if you have multiple fonts then SDF fonts can be a huge win in both size (only need 1) and quality (looks fantastic at both small and large sizes)
There is now an easy to use npm module which generates SDF textures and metadata available here.
People are exploring storing the cubic curves on the GPU and bypassing the texture entirely via having a smart fragment shader do all the heavy lifting of rendering.
This blog has a summary of Font Rendering as of February 2017.
For my current project I use an HTML5 2D canvas to render text and other 2D primitives and overlay it using transparency over the WebgGL canvas. I was surprised at the resulting speed, it beats all other methods described here in speed and quality is very good.
As long as your text is static 2D and you do not need any 3D transformations, this would be my recommendation. In my project this is about 2 times faster than the previous method I used (Font as Geometry).