**EDIT: Please see my other answer with a concrete solution.**

I have actually solved this exact problem over a year ago for my master's thesis. In the Valve paper, they show that you can AND two distance fields to achieve this, which works as long as you only have one convex corner. For concave corners, you also need the OR operation. This guy actually developed some obscure system to switch between the two operations using four texture channels.

However, there is a much simpler operation that can facilitate both AND and OR depending on the situation, and this is the principal idea of my thesis: **the median of three**. So basically, you use exactly three channels (ideal for RGB), which are completely interchangeable, and combine them using the median operation (choose the middle value out of the three).

To accomodate anti-aliasing, we don't work with just booleans, but floating point values, and the AND operation becomes the minimum, and the OR becomes the maximum of two values. The median of three can indeed do both: if *a* < *b*, for (*a*, *a*, *b*), the median is the minimum, and for (*a*, *b*, *b*), it is the maximum.

The rendering process is still extremely simple. The entire fragment shader including anti-aliasing can look something like this:

```
int main() {
// Bilinear sampling of the distance field
vec3 s = texture2D(sdf, p).rgb;
// Acquire the signed distance
float d = median(s.r, s.g, s.b) - 0.5;
// Weight between inside and outside (anti-aliasing)
float w = clamp(d/fwidth(d) + 0.5, 0.0, 1.0);
// Combining the background and foreground color
gl_FragColor = mix(outsideColor, insideColor, w);
}
```

So the only difference from the original method is computing the median right after sampling the texture. You will have to implement the median function though, which can be done with just 4 min/max operations.

Now of course, the question is, **how do I build such a three-channel distance field?** And this is the tricky part. The most obvious approach that I took in the beginning was to perform a decomposition of the input shape/glyph into three components, and then generate a conventional distance field out of each. The rules for this decomposition aren't that complicated. Firstly , the area with at least 2 out of 3 channels on is the inside. Then, if you imagine this as the RGB color channels, convex corners must be made of a secondary color, and its two primary components continue outward. Concave corners are the inverse: Two secondary colors enclose their common primary color, and the wedge between where both edges continue inward is white. I also found that some padding is necessary where two primary or two secondary colors would otherwise touch to avoid artifacts (for example, in the middle stroke of the "N" in the picture).

The following image is an example decomposition generated by the program from my thesis:

This approach however has some drawbacks. One of them is that the special effects, such as outlines and shadows will no longer work correctly. Fortunatelly, I also came up with a second, much more elegant method, which generates the distance fields directly, and even supports all of the graphical effects. It is also included in my thesis and so is also over a year old. I am not going to give any more details right now, because I am currently writing a paper that describes this second technique in detail, but I will post it here as soon as it's finished.

Anyway, here is an example of the difference in quality. The texture resolution is the same in each image, but the left one uses a regular texture, the middle one uses an ordinary distance field, and the right one uses my three-channel distance field. The performance overhead is only the difference between sampling an RGB texture versus a monochrome one.

As a matter of fact Adam already posted source code on shadertoy. Here's the link: https://www.shadertoy.com/view/ltXSDB

– Felipe Lira – 2015-08-21T13:02:37.213You had me excited. He did post the bezier stuff on shadertoy but not the texture distance field stuff! – Alan Wolfe – 2015-08-21T14:33:14.070

@AlanWolfe I think he has done only for procedurally set bezier curves. I'm not sure the effort required to integrate this into a ttf render lib. When I have some time I'll take a look at it. – Felipe Lira – 2015-08-21T22:07:14.407

it looks he has some magic sauce on the side of actually storing and retrieving the distances from a texture. Without a texture in play, the shadertoy examples are missing that part of the equation. – Alan Wolfe – 2015-08-21T22:11:30.443

Bit late to the party but this older thread from reddit has a ton of info on various methods of improving the sharpness of SDF based rendering: https://www.reddit.com/r/gamedev/comments/2879jd/just_found_out_about_signed_distance_field_text/

– Necrolis – 2015-08-31T21:56:04.753