Deformers: bend, taper, shear

You cannot push vertices around in a distance field, because there are none. What you can do is change the question. Transform the query point before evaluating, and the shape appears bent, tapered or sheared without the shape function knowing anything happened.

One box function, four domains. Straight, bent, tapered, sheared. Watch the distance bands, not just the silhouette.

Each one is two lines

// bend: rotate by an angle that varies along y
vec2 bend(vec2 p, float k){ return rot(k * p.y) * p; }

// taper: scale x by a factor that varies along y
vec2 taper(vec2 p, float k){ p.x /= (1.0 + k*p.y); return p; }

// shear, the 2D stand-in for twist
vec2 shear(vec2 p, float k){ p.x += k*p.y*p.y*sign(p.y); return p; }

They compose. Bend then taper is a different shape from taper then bend, and both are valid, which is most of the expressive range of this technique.

The part that bites: your distance stops being a distance

A rotation is an isometry, so bending by a constant angle is free and exact. The moment the transform varies with position, it stretches or compresses space, and the value you get back is no longer the true distance to the surface.

Which direction it goes matters enormously. If the warp compresses space the returned value overestimates, and a sphere trace using it will overstep and punch through the surface. Watch the distance bands in the demo: where they bunch together, the field is lying, and by how much they bunch is roughly how much.

The fix, and its cost

Divide by a Lipschitz bound: the largest amount the warp can stretch space anywhere it is used. For the taper above, that bound is driven by the maximum of 1 + k*p.y over your domain. Dividing by it makes the field conservative again, and the price is a field that understates everywhere else, so tracing gets slower.

In 2D, where there is no march, none of this matters for drawing the shape. It matters the moment anything else consumes the field: glow width, outline thickness and soft shadows all read distance, and all of them will be subtly wrong in the warped region if you skip the bound.

Rules of thumb

  1. Transform the query point, never the shape. The shape function stays untouched.
  2. Apply warps in the reverse order you want them to read, since you are undoing them.
  3. A position-varying warp breaks the distance property. A constant rotation or translation does not.
  4. Crowded distance bands are the visible symptom. Look for them before shipping.
  5. Divide by the worst-case stretch if anything downstream reads the distance rather than just its sign.

All 61 notes How to use them Credits