What a field actually costs
A 2D distance field has no raymarch loop to blame. The cost is simply the whole scene function, evaluated once per pixel, for every pixel on screen. Which means the naive version scales with primitive count times resolution, and nothing about it gets cheaper when the object is off in a corner.
Left is uniformly hot, because it is uniformly expensive: a pixel in empty space does exactly the same work as a pixel in the middle of the busiest blend. Right is cold almost everywhere and only pays near the geometry.
Why you can skip, and why you still have to return something
The polynomial smin has compact support: once the two distances differ
by the blend radius k, it returns exactly min. A blob more
than r + 2.5k away has a distance over 2.5k, so it can only
blend where the field is already above 1.5k, and a blend never takes more
than k/4 off. It cannot move the surface, so on the surface skipping it
changes nothing at all. That is exact, not a rounding argument.
But you cannot simply continue and drop the blob, or the field forgets it
is there, and anything that consumes the field off the surface breaks: a march
oversteps, a glow gets the wrong width, an outline lands in the wrong place. The
blob's exact distance is one length, and min keeps it in the
field without the blend:
float toC = length(p - c);
if (toC > r + k*2.5) {
d = min(d, toC - r); // exact on the surface, up to k/4 high off it
continue; // skip the real evaluation
}
Be careful what that buys. Swapping min in for smin can only
make the field larger, because smin is never above min. So
off the surface this is NOT a lower bound: it can read up to k/4 high,
which is the unsafe direction for a march. For drawing, as here, it does not matter.
A raymarcher leaning on it should step by d - 0.25*k.
The honest accounting
The branch is not free. GPUs execute in lockstep across a group of pixels, so a group straddling the boundary pays for both paths, and the win only appears when whole groups skip together. That is why this works well for scattered blobs and poorly for thin structures spread across the frame: coherence is what you are actually buying.
Which also means the counter in this demo is optimistic. It counts evaluations per pixel, and the hardware charges per group. Treat the heatmap as showing where the opportunity is, not as a frame time.
Rules of thumb
- Cost is primitives times pixels. Neither factor cares where the object is until you make it care.
- Every early-out must still return the skipped shape's distance. Know which way the error goes:
minforsminreads up tok/4high. - Bound by radius plus blend radius. Forgetting the blend term clips the fillet and it shows.
- Wins come from whole groups skipping together, so scattered clusters beat thin spread-out structures.
- Measure with a heatmap before optimizing. The expensive pixels are rarely where they feel like they are.
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.