t is not distance along a curve
A Bezier is defined by a parameter t from 0 to 1, and it is enormously
tempting to treat that as position along the curve. It is not. The curve moves at
different speeds through different parts of its own parameter range, and everything
you place by t inherits that.
Left, the markers bunch up in the tight hook and stretch out along the lazy opening,
even though t was stepped in perfectly equal increments. Right, they are
evenly spaced along the curve, which is what "evenly spaced" almost always meant.
Why the parameter is not the distance
The speed along a curve is the magnitude of its derivative, |B'(t)|, and
for a cubic that varies with the control polygon. Where control points are far apart
the curve covers a lot of ground per unit of t; where they bunch, it
crawls. A useful rule of thumb: the speed ratio is roughly the ratio of the
longest to shortest control-polygon segment, and that ratio is exactly how
unevenly your markers will land.
Which also tells you when you can ignore all of this. A gentle curve with a near-even
control polygon has a speed ratio near one, and stepping t is fine. The
problem appears with hooks, cusps and anything with a tight end.
The fix is a small table
// build once
float len[N+1]; len[0] = 0;
for (i = 1..N) len[i] = len[i-1] + |B(i/N) - B((i-1)/N)|;
// then invert: given a target LENGTH, find the t
find i where len[i] >= target
f = (target - len[i-1]) / (len[i] - len[i-1])
t = (i-1 + f) / N
There is no closed form for the arc length of a cubic, so a table is not a shortcut, it is the standard answer. Twenty samples is plenty for one curve segment; the remaining error is far below what you can see at drawing sizes.
Everything that lands on a curve needs this
- Dashes and dots. Uneven spacing is the most visible version.
- Anything repeated along a stroke: studs, scales, rungs, a chain.
- Constant-speed motion. A thing traveling by
tspeeds up and slows down for no reason, which reads as a physics bug. - Texture along a stroke. A pattern parameterised by
tstretches and squashes. - Flattening to line segments. Equal
tsteps put too many segments in the straight part and too few in the tight bend, which is the part that needed them.
Rules of thumb
tis a parameter, not a distance. They coincide only for a straight line.- Estimate the speed ratio from the control polygon before deciding it does not matter.
- Build a cumulative length table and invert it. Twenty samples per segment is enough.
- Interpolate inside the table bracket rather than snapping to the nearest sample.
- Rebuild the table when the curve changes, not every frame for a static one.
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.