A flying piece needs every term in its own frame

Once a shape is cut, each piece wants its own position and rotation. The transform itself is trivial and free of error, which is why the actual bug is somewhere else: a piece is built out of several terms, and it only stays rigid if all of them move together.

A disc cut into five wedges and thrown. Left: one of each wedge's two cut planes rotates with the piece but stays pinned to the world origin. Right: every term in the piece's own frame.

On the right the wedges are rigid: they translate and spin and their shape never changes, because there is nothing in their construction that can. On the left they swell into half-discs and clump, because one of the two planes cutting each piece is still standing where the disc used to be, re-cutting it from a place it has left. Only one term out of three is wrong and the piece is unrecognisable.

Rigid transforms are exact, which is the good news

Rotation and translation preserve distance. So evaluating a field at rot(p − pos, −angle) gives you a true distance field of the moved shape, with no correction factor and no gradient fixup. This is not an approximation that holds for small motions; it is exact for any motion.

vec2 q = rot(p - pos, -angle);   // into the piece's frame
float piece = max(body(q), cut0(q), cut1(q));   // EVERY term takes q

Scaling is the one that is not free. A field scaled by s must have its result multiplied back by s, or every distance it reports is wrong by that factor and everything downstream inherits it.

Why it is always a cut plane

Because the body usually survives the mistake. A circle is rotation invariant, so forgetting to rotate it changes nothing, and a capsule or a box drawn from a center survives a forgotten rotation about that same center. The cut planes are the terms that are defined relative to the original shape rather than to the piece, so they are the ones somebody wrote before the piece existed.

A structural fix beats vigilance here. Compute q once at the top of the piece's scope and never mention p again inside it. Any appearance of p below that line is the bug, and it is greppable.

What actually drives the pieces

Nothing that needs a physics engine, at this scale:

That last one is worth defending. An integrated simulation makes the shatter unrepeatable and unseekable, which is exactly wrong for anything that has to look the same in a trailer as it did in the build.

The cost, and where it stops being free

Every piece is evaluated at every pixel, so the cost is linear in piece count over the whole screen. Five is nothing. Forty is a real bill and wants a bound: a cheap bounding circle per piece, tested first, that skips the piece's terms when the pixel is far outside it. The branch is coherent enough to be worth it because pieces are spatially compact.

Rules of thumb

  1. Compute the local point once per piece, and let no term inside the piece see the world point.
  2. Rotation and translation are exact and need no correction. Scale needs its factor put back.
  3. If a piece changes shape as it moves, a cut plane is in the wrong frame. It is almost never the body.
  4. Drive it from one time value rather than integrating, so the whole thing is seekable.
  5. Past roughly a dozen pieces, add a per-piece bounding test before evaluating its terms.

All 61 notes How to use them Credits