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. Outside the bite they curve around the hole's circle, a surface that is no longer there, instead of rounding off the two tips, and they kink along a crease that has nothing to do with the visible boundary. The red is measured against the exact field of the same shape. It comes and goes: while the hole sits wholly inside the body, the carve is exact and there is nothing to mark.
Why it happens
Each argument of the max is an exact distance to its own circle. Where
the hole has bitten through the rim, the point outside the shape that is nearest the
bite takes the hole's value, which is its distance to the hole's circle. But most of
that circle is no longer part of the shape. The real surface is further away, round
the tips of the bite, so the returned value is smaller than the true
distance, by as much as a third of the body's radius here.
You cannot catch this by checking the gradient. Both branches have slope one, so the
result has slope one almost everywhere, even where its value is wrong. A field that
reads like a distance to every local test and is still not one is exactly what
Inigo Quilez means when he says the max operators produce bounds.
A bound is the safe direction for a march. A sphere trace stepping by that value takes shorter steps than it could, so it costs iterations, but it never steps through anything. What it does break is everything that reads the number as a distance.
What breaks, in order of how quietly
- Nothing, visually. The silhouette is exact. This is why it survives.
- Glow, outlines and rounding reach too far near the bite, because all three read distance directly. An outline drawn at a fixed distance fills in the bite's corners instead of following its tips.
- Bevels and normals get a crease along the seam, outside the bite where the true field is smooth, and a central-difference normal there averages two unrelated directions.
- Marching slows down near the bite. It cannot tunnel, since the steps only get shorter, but a scene built from many carves pays for it in iterations.
What to do
There is no free exact fix, and it is worth saying that plainly rather than pretending. The options are:
- Accept it where only the sign or a march uses it. A bound is safe to march and draws a perfect silhouette. Keep it away from anything that reads the value as a distance.
-
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, and the shape in this demo has one too: a circle minus a circle is Inigo Quilez'ssdMoon, which is what the red is measured against.
Rules of thumb
max(a, -b)is correct in sign everywhere, exact inside, and short outside where the hole breaks the rim.- It underestimates. That is the safe direction for a march and the wrong one for anything that reads the number.
- A gradient check will not find it. Compare against an exact field.
- 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 and something reads the distance, find the exact formula or keep the carve out of that path.
If you find anything wrong, let me know at hello@andrewdetwiler.com and I'll get it updated.
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.