惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

月光博客
月光博客
MyScale Blog
MyScale Blog
博客园 - Franky
The Cloudflare Blog
IT之家
IT之家
Blog — PlanetScale
Blog — PlanetScale
博客园 - 聂微东
WordPress大学
WordPress大学
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
The Blog of Author Tim Ferriss
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
罗磊的独立博客
Google DeepMind News
Google DeepMind News
P
Proofpoint News Feed
Martin Fowler
Martin Fowler
aimingoo的专栏
aimingoo的专栏
J
Java Code Geeks
腾讯CDC
雷峰网
雷峰网
Microsoft Azure Blog
Microsoft Azure Blog
G
Google Developers Blog
博客园 - 【当耐特】
美团技术团队
云风的 BLOG
云风的 BLOG

Red Blob Games: latest blog posts

Red Blob Games: Differential heuristics Red Blob Games: Responsive design calculator Red Blob Games: Academic citations Red Blob Games: Highlighting interactive code blocks Red Blob Games: Optimizing page size Red Blob Games: Writing a guide to SDF fonts Red Blob Games: URLs with trailing punctuation Red Blob Games: What I did in 2025 Red Blob Games: Goodbye Sass Goodbye Sass Red Blob Games: RotMG map seeds Red Blob Games: Mapgen4 Mapgen4's use of WebGL2 Red Blob Games: Mapgen4 river shader Red Blob Games: Mapgen4 renderer Red Blob Games: Harnessing ChatGPT hallucinations Red Blob Games: Let Let's write a search engine, part 2 of 2 Red Blob Games: Let Let's write a search engine, part 1 of 2 Red Blob Games: Hexagon conversions Red Blob Games: Mapgen4 trade routes Red Blob Games: De-optimizing mapgen4 Red Blob Games: Hexagon spiral coordinates Red Blob Games: Thoughts on Flash Red Blob Games: What I did in 2024 Red Blob Games: Hexagon page animations Red Blob Games: SDF Halos SDF Halos Red Blob Games: SDF headless tests, part 2
Red Blob Games: SDF antialiasing
2024-09-22 · via Red Blob Games: latest blog posts

Last time I was looking at letter spacing with my renderer to see how it compared to Google Chrome on Mac. But while doing that I noticed that their antialiasing looked nicer than mine. So I tweaked parameters, including antialias edge width, gamma, and threshold bias.

My renderer Google's renderer
My renderer (first) vs Google’s (second)

I got results that were close to Google Chrome on Mac, but beyond that it became unclear which variant was actually better. I kept tweaking parameters:

tweak 0 tweak 1 tweak 2 tweak 3 tweak 4 tweak 5
Many attempts to tweak parameters

Sometimes it came down to looking really closely at the pixels. But which is better? I don’t know.

My renderer Google's renderer
My renderer (first) vs Google’s (second)

I realized after a while that this is a rabbit hole. I had to force myself out of this endless tweaking cycle. Besides, Chrome on Mac is different from other browser + windowing systems, so I shouldn’t spend all my time trying to match it.

But two months later, I revisited antialiasing, because I needed to better understand it to implement halos and drop shadows. This happens a lot with my experiments. I’ll discover something, then I’ll tweak a lot, then I’ll put it away for a while, and later I can come back to it and try to understand what I did.

To implement antialiasing let’s look at the mapping from distance to color.

Distance maps to either black or white

Here’s the output. Pixels are either black or white:

The letter e rendered with no antialiasing

For antialiasing we want to smoothly transition between colors, so that it looks like this:

The letter e rendered with antialiasing

But how much? If we do too much, it looks blurry:

The letter e rendered with more antialiasing

We want it to scale based on the output pixels, not the input distance field. And that means we need to know something about the number of pixels on screen.

On the msdfgen page there’s a shader that includes antialiasing. They’re measuring screenPxRange representing how many pixels in the output corresponds to one “distance unit” in the signed distance field input.

If we want antialiasing to occur over edge_blur_px pixels in the output, we can divide edge_blur_px ÷ screenPxRange to find out what signed distance range this represents. For example if we want to antialias over 2 pixels, and screenPxRange is 8 px / distanceunit, then 2 px ÷ 8 px / distanceunit is ¼ distanceunits. The msdfgen code will antialias between 0 and +¼. Another option would be to antialias between −⅛ and +⅛.

This is what the blending looks like:

Color blends between black and white

The slope of that line is screenPxRange / edge_blur_px.

I wanted to get a better sense of what edge_blur_px should be. Over how many pixels should I apply antialiasing? I had previously tweaked it, then made the antialiasing width an interactive parameter to tweak faster. When I revisited it a few weeks later, I realized it’d be better to see all the outputs at once instead of using interactivity to see one at a time. For more on one interactive vs multiple non-interactive visualization, see Bret Victor’s page about “Ladder of Abstraction”[1].

Testing a range of antialiasing widths

I had set edge_blur_px to 1.0 in my previous tweaking, and this confirms that 1.0 is a reasonable choice. Lower values from 0.5 down look a little blocky, and higher values from 2.0 up look a little blurry. I decided to zoom into that range:

Testing a range of antialiasing widths

These may all look the same at first, but look closely with a magnifying glass and you’ll see differences. From eyeballing this, I think maybe 1.2 or 1.3 might be the best choice, at least for large text. I don’t have any explanation for this. Could be it 1.25? Could it be sqrt(1.5)? If I looked at other sizes and characters, would I conclude it has to be higher, like sqrt(2) or 1.5? Is there signal processing math to prove the best value? Would it be different with gamma correction? Should I use smoothstep instead of linearstep? I don’t know. I’ll set it to 1.2 for now.

I’m quite happy with what I have, but not happy with how long it took. Two months went by between the first and last image on this blog post. I had many fixes and tweaks in those two months. I’ll describe those in the next few posts.

[Update: This is a great post about antialiasing with distance fields: https://blog.pkh.me/p/44-perfecting-anti-aliasing-on-signed-distance-functions.html[2]]