Recent

Author Topic: Distance field fonts  (Read 7313 times)

ChrisR

  • Full Member
  • ***
  • Posts: 247
Distance field fonts
« on: July 06, 2017, 06:19:37 pm »
The text.lpr (OpenGL Core 3.3) and textLegacy.lpr (OpenG2.1) projects provide a unit for generating distance field fonts:

https://github.com/neurolabusc/OpenGLCoreTutorials

These projects are cross-platform (Mac, Linux, Windows). In addition to the two included fonts, one can load any fonts generated by Hiero. The shaders use super-sampling to enhance the curves. On MacOS the Core version can show retina-resolution (requires SVN version of Lazarus). As demonstrated, you can load multiple fonts, and you can draw them at any size, color or angle. I think this extends previous work described on this forum:

https://forum.lazarus.freepascal.org/index.php/topic,30632.0.html
http://forum.lazarus.freepascal.org/index.php/topic,30556.0.html

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11382
  • FPC developer.
Re: Distance field fonts
« Reply #1 on: August 10, 2017, 11:21:46 am »
(Holidays quiet of summer work-at-home period, starting up opengl work again, hence the necro post).

I looked at it and notice you use a different frag shader, will have to study that and the advantages. (most notably the sample is the median of a vector). You seem to use Hiero just fine (I failed miserably to get it to generate SDF fonts over christmas 2015)

I see you didn't implement the scaling after upload with an upload, nor the packing of the character data (probably because of the need for the GEOM shader for that).  (12x4 bytes vs 16x4 bytes, but some of those 12 are added to make the scaling work)

Can you say anything else about the differences?

ChrisR

  • Full Member
  • ***
  • Posts: 247
Re: Distance field fonts
« Reply #2 on: August 12, 2017, 01:47:49 am »
The page includes two projects. the textmain uses the classic signed distance field algorithm. This is essentially the method described by https://github.com/libgdx/libgdx/wiki/Distance-field-fonts, though I found I could improve it a bit using a shader-based super-sampling http://www.java-gaming.org/index.php?topic=33612.0. For this first project you use Hiero, which packs the fonts nicely. Another advantage is we only need to retain the alpha channel, so the texture takes very little space on the GPU. The downside of this approach is you do not get sharp corners, and it appears a bit blurry to my eyes.

The mtextmain project uses Multi-channel signed distance field https://github.com/Chlumsky/msdfgen to retain those sharp edges. As you note, it uses the specialized shader described on the home page. The tool I used to generate these fonts is https://github.com/Jam3/msdf-bmfont, which is less efficient than Hiero at packing in the fonts and a bit harder to use. However, the results are sharper.

For both projects, I set it up so you can use the mouse scroll wheel to adjust the scaling. A major benefit of SDF versus conventional OpenGL fonts is that you can use a single size texture and scale it up or down in size with very little artifacts.

The Hiero files are packed much more efficiently than the msdf fonts, but in both cases I read the Hiero-format files to select the location in the texture for each character. This allows my software to work even when different characters like the "M" and "." take up very different amounts of the texture.

The first approach is like your approach earlier standaloneglv3. I did make the code cross-platform,  and wrapped the font as an object so it is easier to drop into other projects. However, the results are the same.
« Last Edit: August 12, 2017, 02:02:11 am by ChrisR »

ChrisR

  • Full Member
  • ***
  • Posts: 247
Re: Distance field fonts
« Reply #3 on: August 12, 2017, 02:32:21 am »
Here is a screenshot showing the standard SDF (top) and Chlumsky's multi-channel SDF (bottom).

ChrisR

  • Full Member
  • ***
  • Posts: 247
Re: Distance field fonts
« Reply #4 on: August 12, 2017, 05:45:36 am »
By the way, for the SDF fonts I did not pack the fonts into different planes. Instead I used "glTexImage2D(... GL_RED" instead of ""glTexImage2D(... GL_RGBA" to use 25% of the texture memory. Obviously I can not use that trick with the msdf fonts.

By the way, soimy has just provided a much better packing method for the msdf fonts https://github.com/Jam3/msdf-bmfont/pull/15 so I will release a new version of my software soon that takes advantage of this.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11382
  • FPC developer.
Re: Distance field fonts
« Reply #5 on: August 14, 2017, 02:44:15 pm »
By the way, for the SDF fonts I did not pack the fonts into different planes. Instead I used "glTexImage2D(... GL_RED" instead of ""glTexImage2D(... GL_RGBA" to use 25% of the texture memory. Obviously I can not use that trick with the msdf fonts.

By the way, soimy has just provided a much better packing method for the msdf fonts https://github.com/Jam3/msdf-bmfont/pull/15 so I will release a new version of my software soon that takes advantage of this.

Btw, I couldn't get the 32-bit to run. If I toggle the define, it (intendedly) breaks on the line  (gltext)

Code: [Select]
  Change ").r" to read ").r" in kFrag and kFragSuper

I think something went wrong there with some global replace, since changing something to the same doesn't make sense :-)

It is interesting to me, since the program still runs, and has exactly the same problem as my own programs (fonts looking very fat), and I also still use 32-bit textures.

P.s. formdestroy should be outside the retina ifdef in "textmain"
« Last Edit: August 14, 2017, 02:46:20 pm by marcov »

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11382
  • FPC developer.
Re: Distance field fonts
« Reply #6 on: August 14, 2017, 02:49:56 pm »
For both projects, I set it up so you can use the mouse scroll wheel to adjust the scaling. A major benefit of SDF versus conventional OpenGL fonts is that you can use a single size texture and scale it up or down in size with very little artifacts.

(I meant without scaling by just setting an uniform, rather than recalculating and reuploading vertices, this allows the scene to scale while fonts scale independently and remain readable)
« Last Edit: August 15, 2017, 12:18:12 pm by marcov »

ChrisR

  • Full Member
  • ***
  • Posts: 247
Re: Distance field fonts
« Reply #7 on: August 15, 2017, 04:27:13 pm »
Marcov - thanks for your feedback. Having an advanced user like you test my project on multiple platforms is a great help.

1) I have updated the project using the new font atlas. I am traveling and only have an access to MacOS, so please tell me if you have any issues. For example, you state you had problems with the 32-bit version but it would help to know the OS (Windows, MacOS, Linux) and widgetset you used. Hopefully my update fixes your problem.

2) My original code did do the font scaling in the shader instead of when generating the outlines. That is a valid approach. However, this required multiple draw calls (with uniforms changed for each call) when you were displaying different font sizes. The approach I ended up with allows all the text to be created with a single draw call, which is nice when you have static text in an opengl scene.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11382
  • FPC developer.
Re: Distance field fonts
« Reply #8 on: August 15, 2017, 05:02:10 pm »
For example, you state you had problems with the 32-bit version but it would help to know the OS (Windows, MacOS, Linux) and widgetset you used.

With the 32-bit I meant 32-bit fonttexture iow turning off TEX8BIT_NOT32. But the behaviour is the same on windows win32 and win64 bit. It just seems to plot all pixels that are not 0 in the sdf.

2) My original code did do the font scaling in the shader instead of when generating the outlines. That is a valid approach. However, this required multiple draw calls (with uniforms changed for each call) when you were displaying different font sizes. The approach I ended up with allows all the text to be created with a single draw call, which is nice when you have static text in an opengl scene.

I also have only draw call, so I have two scaling mechanism. One "relative" size per character so that each string can have its own size, and one zoom factor that sets the absolute size (usually linear with 1/zoom of the rest of the scene).

This way, the texts are attached to the same position of the rest of the scene (same ModelViewProjectionMatrix) when zooming, but the size can change. To achieve that, I store the distance to the topleft corner of the first character of each string in each character. 

To avoid bloating the per character record, I only add what I need and calculate the rest in the geometry shader, and I don't support rotating (since that would require a length and an angle, and I rarely use it).

The geometry shader also implements a layer system, so you can reduce detail without reuploading. (in case there are too many primitives if you are zoomed out and it becomes a soup).

I got supersampling working today, and it looks nice (remarkable improvement for small texts), but I still have a small problem in my coordinate systems (x,y too large). Something for tomorrow.


 

TinyPortal © 2005-2018