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

推荐订阅源

D
Docker
F
Fortinet All Blogs
爱范儿
爱范儿
博客园 - Franky
MyScale Blog
MyScale Blog
罗磊的独立博客
博客园 - 三生石上(FineUI控件)
B
Blog
P
Proofpoint News Feed
IT之家
IT之家
宝玉的分享
宝玉的分享
D
DataBreaches.Net
S
SegmentFault 最新的问题
Microsoft Azure Blog
Microsoft Azure Blog
GbyAI
GbyAI
M
MIT News - Artificial intelligence
L
LangChain Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
月光博客
月光博客
雷峰网
雷峰网
Stack Overflow Blog
Stack Overflow Blog
量子位
V
V2EX
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

Red Blob Games: latest blog posts

Red Blob Games: English: a vs an 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 combining distance fields
2024-09-28 · via Red Blob Games: latest blog posts
Blog post: 27 Sep 2024

Learning about font rendering, I was looking at text closely last time, and I noticed another issue. The shadows of each letter overlap the previous letter. That’s because I’m drawing one letter at a time. So for example in the fl, I draw the f’s letter, outline, and shadow, then I draw l’s letter, outline, and shadow. So l’s shadow is drawn on top of f’s letter.

Shadows of each letter overlap the previous letter
Closeup showing the shadow drawn over the character to the left

The first thing I considered was to draw all the shadows first and then draw all the letters. But a second problem here, harder to see, is that shadows are drawn on top of the adjacent letter’s shadows, and that causes them to be darker than they should be. The distance fields for adjacent letters always overlap:

Sprite distance fields always overlap

It’s only when the letters are close enough that you can see artifacts of the double rendering.

To solve both problems, I can generate a new distance field which is the min() of the distance fields for each character. The min() of signed distance fields is the union of the shapes. I used the blendEquation()[1] function with MAX_EXT instead of the default FUNC_ADD (it’s max instead of min because msdfgen’s encoding is inverted). The MAX_EXT extension seems to have 100% support[2] in WebGL 1, and is always included with WebGL 2.

Adding an intermediate distance field texture

The output texture holds a combined distance field. I then use the distance field shader to draw that combined distance field to the map.

I could do this once per string I want to draw or once for the entire scene. I decided to do it once per string, because that allows me to use different colors and styles (thickness, outline width, shadow, halo) per string.

I ran into a few bugs with this:

  • because I couldn’t figure out how to min() msdf fields, I put an sdf in the combined distance field instead of msdf, and that meant the corners of fonts got a little rounder; to compensate I increased the resolution of the combined distance field
  • having a different resolution for the original and combined distance fields messed up the antialiasing; in the previous post I described a “slope” of distance field vs output pixels, but now there’s an intermediary with the slope stretched out
  • the letters got out of alignment when I moved them around for the intermediate texture; in particular, I had to calculate a new baseline position accounting for the change in resolution

One way I compared parameters was by rendering them in alternating frames. Here’s an example showing that the combined distance field resolution matters (slightly):

Comparison of 3X vs 5X resolution on the combined distance field

Here’s the final result, showing that the overlapped drawing is fixed, especially at the bottom left of the second g:

 
Before and after combining distance fields

The combined distance field approach solves the problem but it means I need to write each string to a separate intermediate texture, which leads to a rabbit hole of having to allocate texture space during rendering, possibly reusing textures, and dealing with gpu pipeline stalls. That’s an area I don’t understand well. Fortunately I don’t need it to be optimized for my project. But for a game project, I might choose to do the two pass approach instead, letting the shadows get drawn twice in overlapping areas. Are there better approaches? I don’t know.