Signed Distance Field Fonts

 from Red Blob Games
23 Mar 2024

Each week I pick one or two things to work on. In week 2 of this year, I decided I should update my “hello world” OpenGL+Emscripten code[1] from 2015. It’s boilerplate I use occasionally in other projects. It wasn’t compiling anymore, and I wanted to fix that as well as several other things.

One of the unsolved issues in that starter code was that the fonts never looked good. I was using the stb_truetype[2] library, and got this output:

screenshot of stb-truetype rendering, with my old code

Look at how H and e are too far apart, and S and D are too close together. I tried various things but couldn’t figure it out, so I had two workarounds at the time:

  1. Use Omar Cornut’s Dear ImGui[3], which has nice looking font rendering.
  2. Use a monospace font to hide the spacing problems.

I decided to look into it again. After all, Dear ImGui uses stb_truetype, so why would my output be so different? After looking through the docs and also several examples, I concluded that my code was all wrong. I tried kerning but that wasn’t the issue. I tried a few different fonts but that wasn’t the issue. One issue on stb_truetype[4] suggests “left side bearing”. I found example code from Justin Meiners[5] that rendered nicely, and it was using left side bearing. But Dear ImGui doesn’t use it. And example code from Benjamin Attal[6] didn’t use it either. I spent many hours studying the docs and examples before I figured out how to rewrite my code[7]. It looks better now (although still not great — look at the gap between m and o):

screenshot of stb-truetype rendering, with my new code

This awakened my desire to play with font rendering. In particular, back in 2016 I bookmarked[8] with the note:

Multi-channel distance fields can represent sharp corners, unlike Valve’s original paper, which had rounded corners. This is C++ code to implement the algorithm described here:[9] (there’s also a thesis paper)

So I decided week 3’s project would be to try that out! It was a great week. I learned a lot.

screenshot of msdf rendering using msdfgen's library

Along the way I kept some notes about what commands I ran and what I learned. These notes were originally meant for myself only but I’m making them available because I think sometimes people don’t realize what my learning process is like. My articles especially present everything in the “final form” and readers might think I just write code like that from the start. I don’t! I have lots of bugs and dead ends and misconceptions along the way. I find that keeping a journal (for myself) helps me work through them.

Some high level notes:

Take a look my notes, as well as an interactive demo I used for testing my knowledge. Random tidbit: the 2403 in the url means year=2024 week=03. I’ve been using this naming scheme since 2015 for my weekly projects.

After playing with fonts week 2 and week 3, I still had more I wanted to do. But I am trying to keep to a project-per-week rhythm, so I decided to wrap up the basic font rendering and move on. In week 4 I’ll explore outlines and other effects. That’s the next blog post.

Email me , or tweet @redblobgames, or comment: