Subtraction lies, and only the sign is honest
Carving one shape out of another is max(a, -b), it is in every reference,
and it is correct. It is correct about which side of the surface you are on.
It is not correct about how far away that surface is, and everything except the
silhouette depends on the second thing.
The left panel gives no indication that anything is wrong, because drawing a shape uses only the sign of the field. The right panel shows the same field's distance bands, and they kink and crowd along a whole region that has nothing to do with the visible boundary.
Why it happens
A distance field has a specific property: its gradient has magnitude one nearly
everywhere, because moving a meter away from a surface increases your distance by a
meter. max does not preserve that. Where the two arguments cross, the
result switches from following one field to following the other, and the seam between
them is a crease. Near that crease the returned value can be much larger than the true
distance to the nearest surface.
So the field claims you are further from the shape than you are. Which is the dangerous direction: a sphere trace stepping by that value marches straight through geometry it should have hit.
What breaks, in order of how quietly
- Nothing, visually. The silhouette is exact. This is why it survives.
- Glow and outline width vary wrongly near the carved rim, because both read distance directly.
- Bevels and normals get a crease along the seam, and a central-difference normal there averages two unrelated directions.
- Marching oversteps and tunnels. In 2D there is no march, which is exactly why this bug can live in a 2D codebase for a long time and then surface the moment anything is ported.
What to do
There is no free exact fix, and it is worth saying that plainly rather than pretending. The options are:
- Accept it and bound the step. Multiply your march step by a factor under one. Cheap, universal, and slower.
-
Use a smooth subtraction. The
smaxcounterpart ofsminsoftens the crease. It does not make the field exact, but it makes the error continuous, which fixes the normals even where it does not fix the distance. -
Do not carve at all where you can avoid it. Often the shape you
wanted is directly constructible, and a directly constructed shape has an exact
field. A ring is
abs(length(p) - r) - t, not a circle with a smaller circle cut out of it.
Rules of thumb
max(a, -b)is correct in sign and wrong in magnitude near the seam.- It overestimates, which is the overstep direction.
- The silhouette will never show you this. Draw the distance bands.
- Prefer a directly constructed shape over a carved one when both exist.
- If you must carve, either use a smooth version or reduce the march step.
One email when something new goes up. No newsletter, no schedule, nothing else.
Double opt-in, so watch for a confirmation email. Unsubscribe any time.