Generating Distance Fields at Runtime

If you need to create a distance field based on runtime data, or import a different vector format not supported by Keen Vectors, you can use the MsdfRendererFactory.

Note

The generation of SDFs requires the platform it will be running on to support compute shaders.

Setup

Since the distance field generation requires references to some internal Keen Vectors assets, there is a little bit of setup involved.

  1. In the script that will be generating the distance field, add a serialized field of type MsdfRendererHandle;
  2. Initialize the field using CreateHandle() from an editor script, (this only needs to be done once, by serializing you keep the references working);
  3. In your generator script, call Begin(float, DistanceFieldFormat). This will give you an active renderer.

If this sounds a bit annoying, well, it is, but the alternatives were to use a preloaded asset, which would impact the initialization of projects that don't use runtime generation, or Addressables, which is a ridiculously huge dependency to require for such a trivial task. (If you have any ideas how to improve this workflow, I am all ears!)

Usage

Once you have a MsdfRenderer, you can call AddRange(ArraySegment<Curve>) with a bunch of Curves.

The coordinates of the curve are given in pixels of the output texture.

These curves must be colored such that each curve has exactly one color channel in common with the next. You can use SimpleEdgeColoring(Span<Curve>, float), or a more specialized coloring scheme of your own devising.

using var renderer = _handle.Begin();

// As an example, let's create a regular polygon
var curves = new Curve[7];
var radius = 16f;
var center = new Vector2(radius, radius);
var angleIncrement = Mathf.PI * 2 / curves.Length;
for (var index = 0; index < curves.Length; ++index) {
    Vector2 start = VectorUtil.FromPolar(angle: angleIncrement * index, length: radius);
    Vector2 end = VectorUtil.FromPolar(angle: angleIncrement * (index + 1), length: radius);
    
    curves[index] = Curve.LineSegment(center + start, center + end);
}

// Apply coloring
MsdfRenderer.SimpleEdgeColoring(curves, maximumStraightDegrees: 3);

// Add curves to render
renderer.AddRange(curves);

// Execute the rendering
Texture2D result = renderer.Generate(new Vector2Int(32, 32));