nanovg
nanovg copied to clipboard
Distance field fonts
From what I've been studying, this algorithm would greatly improve the rendering of text at a minimal cost since the text is rasterized, also interesting that you can easily draw shadows and outlines
Here are some links : Valve : Valve PDF
Multi-channel signed distance field : MSDFGen
Libgdx (java) : Libgdx Distance field fonts
I think something went wrong with the links, since they all result in a 404 for me
links work fine for me.
I experimented a lot with SDF and MSDFGen, and achieved some beautiful and amazing results. The only issue I have with it is GLES2, and here is why:
to achieve the best text rendering result, you need to find the best smoothing factor for this equation:
float alpha = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance);
and how to calculate smoothing? One trick is to use standard derivative functions. I've seen people do this:
float smoothing = fwidth(distance);
or even this:
float smoothing = 0.7 * length(vec2(dFdx(distance), dFdy(distance)));
There are so many more ways to calculate that smoothing factor, and I can't even tell you which one is better ("mathematically correct but slow" vs "good enough but fast"). The point is, fwidth, dFdx and dFdy are not available in GLES2. If you want to use them in GLES2, you can make use of the GL_OES_standard_derivatives extension if you're lucky enough that it is available on your hardware.
For example, on a raspberry pi, you're in for a huge disappointment. You can still approximate the width/height of a pixel, but it's never going to look as good as the result from fwidthor dFdx/dFdy. Maybe there's a way to get something exactly on par with those, but I haven't figured it out yet. If someone knows how to achieve this without using gpu's standard derivative functions, please let me know! Thanks!
- the derivative functions work fine on every machine and OS I have tried. iOS, OSX, windows.
- would smoothing = 1./rendersize, with vec2 uniform rendersize of the pixel dimensions work? I think you could check for the extension with a precompiler directive and #if its not there default to a simple alternative. This would be a really cool, lightweight and powerful feature to experiment with in a branch. I would be down to test it out and refine with you. You could even have it as a separate but compatible library like nanoSVG.. could be nanoSDFont? :P
I'll note here that the font rasterizer that nanovg uses supports SDF generation nowadays (since its version 1.16 actually, way back in 2017). But the SDF so generated would need to be backed by a shader to render them, and that's the main thing missing in nanovg.
Also, the Slug SDF variation/algorithm has been implemented in an open-source package (also based on stb for glyph data fetching) but the trouble with that is that Slug's algorithm is patented https://github.com/mightycow/Sluggish/issues/1
And on this angle perhaps allowing a custom shader would not be outlandish either. https://github.com/memononen/nanovg/issues/402 The latter would allow e.g. MSDF rendering support to be added without hacking the guts of nanovg.
I see above the concerns with GLES2 and Raspberry Pi not having the shader support needed, but there are applications of nanovg beyond that... I saw this amusing video by the way https://youtu.be/MxcafwjWw24?t=117