Why signed distance fields work


Fonts and special effects for 2D assets.


You may have heard of signed distance fields already.  Their use in games was pioneered by Valve (PDF), and there have been various articles about generating and using them.

Yet they always seem like black magic: how can smooth sharp lines be drawn at almost arbitrary angles from just 4 neighbouring pixels in a bitmap?


It took me a bit of time to get this point: but it helps a lot if you don't think of them as "signed distance fields", they're heightmaps.

The signed distance field indicates how far above or below the water line (the contour of the shape) the pixel is.

So in order to estimate whether a point is above or below the water, you can just interpolate between the four neighbouring points - which is precisely what linear texture sampling does.





Implications

When you think about the signed distance field as a heightmap, it becomes simple to think of effects.


For example to create outlines, that's just the equivalent of a line of sandy beaches around an island.


It also means that you are in fact not limited to rendering monochrome images. True: the texture is magnified and there is no good way to invent detail for the color channels, but you can use a second texture at a different scale as a pattern.

You can even use more than one pattern.


Why? Because that heightmap also contains values above and below that water line. You can't really use the values below the water line because that needs to be transparent so you can't see those pixels anyway, but above the water line you can again define extra levels - the equivalent of climbing up a mountain, encountering fields, forests, snowcaps.


Have a look at this screenshot from Never Eat Anything:

You can see that there's a detailed, high resolution "eyes" texture, smooth letters, and an outline. All of that is just governed by one alpha channel.


What else can you do with it?

If you are going to use a four component bitmap, as you'll likely need to anyway if you are targeting mobile platforms, why not make use of those three color channels?


For example, you can use two color channels to indicate the slope of the "land". That way you can create a fake but very passable lighting effect:

This is actually two shapes: the octagonal button is rendered with a pattern, and the "play" button is rendered in white on top of it.

Both have the slopes encoded in the Red and Green channels.

As suggested by the Valve paper, you can also use multiple colors:

This is a single shape. It uses the alpha channel to display the musical note, uses the Red and Green channels to encode the slope, and uses the Blue channel to encode the diagonal line.


Note that the slope is also applied to the diagonal line. There are limits to what you can do. It is possible to make the shader or the generator more complex to suppress this, but I liked the effect.

It is also possible to create sharp outlines for bitmap images, but it's rather fiddly: the actual smooth outline can only deal with the pixel boundaries, so your detail image needs to be slightly oversized.


All of these images are rendered using a single shader. The "water" and "beach" levels are passed in as vertex attributes, so somewhat fatter letters and wider outlines are possible on a per shape basis. Italics can be applied just by offsetting the top vertices of the shapes.

Everything else (shape texture, detail texture, contour color, primary and secondary color, X and Y lighting factors) are passed in as uniforms.

There is now also a free version: get it on Google Play.