SDF headless tests, part 1

 from Red Blob Games’s Blog
Blog post: 8 Nov 2024

In the last few posts I have shown some of the experiments I did with font rendering. Those experiments were all in the renderer. I’m using msdfgen-atlas to generate the textures used by the renderer, and I wanted to experiment with msdfgen’s parameters. Instead of generating new font data and then reloading the browser, I decided to try “headless” rendering controlled by a shell script.

Testing with different parameters

In my blog post about antialiasing I found that instead of changing a slider, I wanted to see the entire range of outputs at once. I did that here as well. For each parameter value I ran msdfgen and generated an output file. Then I compared all the output files against each other to learn about the effect of each parameter.

Getting my code running in stackgl/headless-gl took a lot of work. My code wasn’t designed to work headlessly. But I also had trouble with the installation process (which needs python?!) and poor interactions with twgl.js not liking headless-gl. I’m not sure what to think of this. Is there another headless gl library I should use? Or maybe I can use gl in the browser, with the File API to save the output to files? Or maybe Electron/Tauri? I was frustrated the whole time, and didn’t take good notes on what went wrong. I should have stopped, taken a break, and evaluated the situation with a level head. But instead I kept pushing through with tweaks and fixes until I got something running. [*Update* maybe I should look at Puppeteer[1].]

In any case, I did get something running, and here are some findings—

The first thing I wanted to test was the effect of the emrange / pxrange parameter.

for test in 1 2 3 4 5 6 7 8 9
do
    ~/Projects/src/msdf-atlas-gen/bin/msdf-atlas-gen \
        -type mtsdf -emrange 0.$test -dimensions 511 511 \
        -font ~/Library/Fonts/FiraSans-Regular.otf \
        -imageout assets/FiraSans-Regular.png \
        -json assets/FiraSans-Regular.json
    node msdfgen-parameters.js
    cp _output.png output/test-emrange-$test.png
done
emrange from 0.1 to 0.9

There’s a lot going on here!

Columns 1 and 2 show that the emrange affects how far out I can draw a halo. The other columns show that when I extend emrange to be higher, the font quality degrades.

Columns 3 through 6 should look the same in every row (except for font quality). But they don’t. The outline thickness changes (see column 4), the font thickness changes (see column 5), and the drop shadow distance changes (see column 6). That means there are bugs in my rendering code. If I hadn’t run this test, I might not have found them.

I thought about these bugs for a while and realized:

emrange affects the slope

The emrange affects the slope of the mapping from distance to the value in the texture. My shader was using the y value, the encoded sdf. But I want be using the x value, the distance value. After I understood what I did wrong, I was able to fix the bugs. The outline thickness, font thickness, and drop shadow distance are now consistent:

fix outline and font thickness to handle emrange

While going through these tests, I found and fixed several other bugs, including how I was using msdf+sdf for outlines and how my drop shadow shader worked.

I’m glad I worked on this headless rendering test, but I had enough trouble making my code working headless that I want to look for an easier approach next time.

In the next post I explored the asymmetric version of emrange.

Email me , or tweet @redblobgames, or comment: