Morphing between two shapes

Built on the polynomial smooth minimum by Inigo Quilez. Sources for this reference

Two fields, one parameter, and you have a morph. It is one of the genuinely magic properties of representing shapes as functions, and the obvious implementation has a failure mode worth knowing before you ship it in a transition.

Star to square. Left: a straight lerp of the two fields. Middle: a smin crossfade. Right: the two shapes alone.

The lerp is not wrong, it is unprincipled

d = mix(sdStar(p), sdBox(p), t);

This does produce a continuous transition, and for shapes that are close it looks fine. What it actually computes is the average of two distances, and the zero set of an average is not the average of two zero sets. So the intermediate surface is a shape that belongs to neither, and the way it gets there is not something you controlled.

Watch the star's points on the left. They do not retract, they dissolve, thinning uniformly until they vanish. Sometimes that is the effect you want. It is rarely the effect you asked for.

The crossfade keeps every frame one object

Push the outgoing shape away by growing its distance, pull the incoming one in, and blend the two with smin:

float K = 0.40;                              // keep this SMALL relative to the shapes
float k = max(0.45*4.0*t*(1.0 - t), 1e-4);   // blend radius, zero at both ends (smin divides by k)
d = smin(a + t*K, b + (1.0-t)*K, k);

Adding a positive constant to a field moves its surface inward by that amount, so a + t*K is the star shrinking away and b + (1-t)*K is the square arriving. In between, the result is a smooth union of those two eroded shapes, which is why the intermediate frames read as one object changing rather than two images cross-dissolving.

The blend radius has to shrink to zero at the ends. With a fixed k, the square at t = 0 is eroded but still sits within k of the star, and the smooth union fills in the star's notches. The first version of this demo did exactly that, and its middle panel never once showed the real star. 4t(1-t) is one at the midpoint and zero at both ends, so the ends are the two shapes and nothing else.

Neither one preserves anything

Worth saying plainly: neither approach preserves area, volume, or feature correspondence. A star point does not become a square corner, because nothing told it to. If you need specific features to map to specific features, that is a different and much harder problem, and a field morph is not the tool.

What a field morph is very good at: transitions where the audience should read "it changed" rather than "point A became point B". Dissolves, reveals, a UI element becoming another UI element, a creature shifting form mid-cutscene.

Rules of thumb

  1. Prefer the smin crossfade, and take its blend radius to zero at both ends so the ends are the real shapes.
  2. Adding a constant to a field offsets the surface. That is the whole mechanism.
  3. Keep the push SMALL relative to the shapes. Both terms are offset at once, so at the midpoint each is pushed by half of it, and too large a value shrinks the morph to nothing exactly halfway through.
  4. Ease t. A linear morph reads mechanical no matter which method you use.
  5. Neither method maps features to features. If you need that, this is the wrong technique.

All 61 notes How to use them Credits

If you find anything wrong, let me know at hello@andrewdetwiler.com and I'll get it updated.