nanovg icon indicating copy to clipboard operation
nanovg copied to clipboard

Distance field fonts

Open RodrigoSantiago opened this issue 7 years ago • 4 comments

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

RodrigoSantiago avatar Feb 10 '18 00:02 RodrigoSantiago

I think something went wrong with the links, since they all result in a 404 for me

zambal avatar Feb 10 '18 07:02 zambal

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!

mean-ui-thread avatar Mar 04 '18 03:03 mean-ui-thread

  1. the derivative functions work fine on every machine and OS I have tried. iOS, OSX, windows.
  2. 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

MacroMachines avatar May 14 '18 03:05 MacroMachines

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

werame avatar Jan 29 '22 20:01 werame