Table of Contents

Understanding Signed Distance Fields

Definition

A "Signed Distance Field" is a mathematical idea where every point in space has a distance from a shape. These distances can be positive, if they are outside the shape, or negative, if they are inside the shape.

This principle allows us to do reason and manipulate these shapes mathematically. For example, if we put this field on the screen, we can draw the shape's fill by painting wherever the distance is negative. Similarly, you can easily create an outline 1 unit thick, by painting whichever points have a distance between 0 and 1.

In the image below, a program has drawn a representation of a star's distance field. The blue region is negative, the orange is positive, and the shape's contour is drawn in white. The waves around the shape represent the change in distance.

A star with multiple groovy lines around it

(Thanks to Inigo Quilez for the shader that generated this image)

Rationale

Signed distance fields, in the mathematical sense, are supposed to be unbounded: they have values all the way out at infinity.

This is what happens with shapes defined purely mathematically, such as the ones available in Freya's "Shapes". However, that means that the set of shapes you can use is limited to the ones that are programmed in, and they have to be composed programmatically, which to be fair, is easy to do, but it means you have to be able to draw a varying-length list of shapes.

GPUs are really bad at handling varying-length structures, they do not like the code (shaders) they run to be different based on the inputs, but they do handle textures very well. Textures are also convenient since they are implemented in every game engine.

Textures, however, cannot have an infinite size, and they have a limited amount of values they can represent.

How Fields are Represented

Since textures must have a finite size, and finite values, the distance values are represented in the color channels, using 8 bits per channel. This means they go from 0 to 255, and, when loaded onto the GPU, they get converted to the range 0.0 to 1.0.

Since we only have 256 distance values to hand out, we say that the range 0 to 127 are the positive distances, with 0 being as far away as possible. 128 to 255 are the negative distances, with 255 being the most inside the shape you can be.

If we were using only a single number, that means that the image would be "whitest" inside the shape, and "blackest" outside.

Pixel Range

Since we have a limited amount of distance values, we have to decide how to spread them out! The scheme used by this asset is to have them spread linearly along a set amount of pixels.

Imagine the "distance" here is "distance from sea level". This means that changes in the field will be like hills and slopes. If you walk straight up or down one of these slopes, eventually you will reach a "plateau", or "sea floor", where moving anywhere will not change your distance from sea level.

The "pixel range" is how far you can walk from the beach until you reach this plateau, or, leaving the analogy, how many pixels away from the shape's contour it takes to reach the limits of our scale.

A larger pixel range allows for effects like outlines and shadows to reach further away from the shape, but also means that precision is sacrificed a little bit.

This value is decided when converting the vector shape into a texture, and must be provided to the renderer so it can know how to unpack the values of the field.

Useful Properties

As was hinted at in the Definition, signed distance fields have some interesting properties:

  • They can be rendered with perfect antialiasing very cheaply;
  • You can perform operations like union, difference, intersection of two shapes with simple mathematical operations;
  • You can easily implement contour-based effects like outlines, shadows, and more.

Resources