B-Splines and NURBS
Suppose you are animating a spaceship along a long, elegant flight path, and near the end you nudge
one control point to clear a moon. With the
Bézier curve
you may know, that single nudge can ripple through the whole curve — the ship's takeoff twitches
because you tweaked its landing. Modellers and technical animators wanted something better: a curve where
moving one handle disturbs only the nearby stretch of curve, and where the same maths can
also describe a perfect circle for a lens, a wheel, or an orbit. That something is the
B-spline, and its rational cousin the NURBS. Together they are the
workhorse curves of CAD, industrial design, and smooth camera paths.
This page builds them from the ground up: piecewise polynomials with local control, the
basis functions woven by the Cox–de Boor recursion, the all-important knot
vector, and finally the weights that turn a B-spline into a NURBS able to draw
exact conics. It assumes you have met plain
splines
already.
A B-spline is a piecewise polynomial glued smoothly
A B-spline curve of order k (degree k-1) is built
from a list of control points P_0, P_1, \dots, P_n and a list
of increasing numbers called the knot vector. Between consecutive knots the curve is a
single polynomial segment of degree k-1; at each interior knot the
segments are joined so that the curve and its first k-2 derivatives match. A
cubic B-spline (k = 4) is thus a chain of cubic pieces that meet with matching
position, tangent, and curvature — which is exactly why the result looks so effortlessly smooth.
The curve is written as a weighted blend of its control points, where the blending
weights are functions of the parameter u:
C(u) \;=\; \sum_{i=0}^{n} N_{i,k}(u)\, P_i .
Each N_{i,k}(u) is a basis function — a little bump attached
to control point P_i that says "how much does P_i
pull on the curve at parameter u?" The whole personality of B-splines lives in
the shape of those bumps.
The basis functions: the Cox–de Boor recursion
The basis functions are not pulled from a hat — they are generated by a beautiful recursion that starts
with flat "boxes" and raises their degree one step at a time.
- Order 1 (degree 0) — a box that is on over one knot span and off elsewhere:
N_{i,1}(u) = \begin{cases} 1 & u_i \le u < u_{i+1}\\ 0 & \text{otherwise.}\end{cases}
- Order k — blend two lower-order bumps with linear ramps:
N_{i,k}(u) = \frac{u - u_i}{u_{i+k-1} - u_i}\,N_{i,k-1}(u) \;+\; \frac{u_{i+k} - u}{u_{i+k} - u_{i+1}}\,N_{i+1,k-1}(u).
Two facts fall straight out of this recursion and define everything B-splines are good for:
- Local support. N_{i,k}(u) is non-zero only on the
k knot spans [u_i, u_{i+k}). So control point
P_i influences only that short stretch of curve — move it and the
rest of the curve does not budge.
- Partition of unity. At every u the active basis
functions sum to 1: \sum_i N_{i,k}(u) = 1, and
each is non-negative. A blend with non-negative weights that add to one is a
convex combination, so the curve always lies inside the convex hull of the
nearby control points — it can never fly off wildly.
Because the ramps in the recursion use the knot spacing, the shape of the bumps depends on how
the knots are spread. That is what "non-uniform" will refer to.
See local control for yourself
Below is a cubic B-spline over nine control points (the faint zig-zag is the control polygon
joining them). The slider lifts and lowers only the middle control point. Watch what
happens: the curve bulges near the middle and is completely unmoved at the two ends. That
is local support in action — a cubic control point touches only the four knot spans around it. Notice too
that the curve does not pass through the control points: B-splines approximate
their control polygon, hugging it without touching. That trade — giving up interpolation — is precisely
what buys the silky smoothness and the locality.
The moving point tugs the nearby curve toward it, but never all the way to it, and the far ends stay put.
The knot vector: uniform, non-uniform, and clamped ends
The knot vector U = (u_0, u_1, \dots) is a non-decreasing list
of parameter values that carves the parameter line into the spans where each polynomial segment lives. Its
spacing and repetition are genuine design knobs:
- Uniform — equally spaced knots (0,1,2,3,\dots). Every
basis function is a shifted copy of one bump; the curve is even and predictable, but its ends do
not reach the first and last control points.
- Non-uniform — unequal spacing. Bunching knots pulls the curve tighter in that
region and lets you place detail where you want it. (The "NU" of NURBS.)
- Clamped / open — repeat the first and last knot
k times (e.g. 0,0,0,0,1,2,3,3,3,3 for a cubic).
The repeated end-knots force the curve to interpolate its first and last control points
and to leave along the first/last polygon edges — the standard choice so a modelled curve actually
starts and ends where you put its endpoints.
A cubic B-spline needs n + k + 1 knots for
n+1 control points of order k. Get that count
wrong and the basis functions don't line up — a classic source of "why is my curve blank?" bugs.
From B-spline to NURBS: add a weight per point
Polynomial B-splines have one stubborn limitation: they cannot draw an exact circle. No
polynomial x(u), y(u) satisfies
x^2 + y^2 = r^2 — a circle is not a polynomial curve, it is a rational
one. The fix is to give every control point a weight
w_i > 0 and take a rational blend:
C(u) \;=\; \frac{\displaystyle\sum_{i=0}^{n} w_i\, N_{i,k}(u)\, P_i}{\displaystyle\sum_{i=0}^{n} w_i\, N_{i,k}(u)} .
- A NURBS is a B-spline whose control points carry weights
w_i, blended as a ratio of two B-spline sums.
- Geometrically it is the shadow (projection) of a polynomial B-spline living one dimension up, in
homogeneous coordinates — the weight is that extra coordinate. This projective trick
is what lets a "curved" polynomial upstairs cast an exact conic downstairs.
- Set every w_i = 1 and the denominator becomes
\sum_i N_{i,k}(u) = 1: the NURBS collapses back to an ordinary B-spline. So
B-splines are just the equal-weight special case.
Worked example: the weight as a magnet
Take five control points and lift the weight of only the middle one. When
w = 1 the NURBS is the plain B-spline (faint curve). As you crank
w up, that control point's term w\,N(u) grows in
both the numerator and the denominator, so near the middle the ratio is dominated by
P_{\text{mid}} and the curve is dragged toward it. Push
w \to \infty and the curve is pinned to that point; drop
w \to 0 and the point loses all pull, as if it weren't there. Drag the slider
and watch the magnet strengthen — while, thanks to local support, the ends stay put.
Why a circle needs this. A quarter-circle is a NURBS with three control points forming a
right angle, using a quadratic basis and a middle weight of
w_{\text{mid}} = \cos(45^\circ) = \tfrac{\sqrt2}{2} \approx 0.707. That precise
weight makes the rational blend trace x^2 + y^2 = r^2 exactly — no
polynomial choice of control points can do it, because the ratio, not any polynomial, is what bends the
arc into a true circle. Change the weight and you get a different conic: a smaller weight gives an ellipse
arc, larger gives a hyperbola-like flare. One formula, every conic.
NURBS hit a sweet spot no other representation matches: they give exact circles,
cylinders, cones, spheres and free-form surfaces in one unified maths, with local editing
(drag a control point, disturb only its neighbourhood) and guaranteed smoothness. A car door and the fillet
where it meets the wheel arch can live in the same NURBS surface. That is why they became the ISO standard
for CAD (IGES, STEP), the native geometry of tools like Alias and Rhino, and a favourite for
camera and motion paths in film — an animator wants a flight path that is buttery smooth
and locally tweakable without re-choreographing the whole shot.
These three cousins behave differently, and grabbing the wrong one picks the wrong tool:
- B-spline — approximating (the curve does not pass through
its control points) with local control (a point moves only a few nearby spans). Great
for smooth, editable modelling and camera paths.
- Bézier — a single Bézier interpolates its two endpoints but only approximates
the interior handles, and control is essentially global across that one segment (move
a handle and the whole curve shifts). Perfect for a single, deliberately-shaped stroke or F-curve
tangent.
- Catmull-Rom — interpolating: the curve passes through every
control point, which is exactly what you want when the points are data samples the motion must hit.
So: need the curve to hit your points? Catmull-Rom. Need a smooth, locally-editable shape that
hugs a control cage, plus exact circles? B-spline / NURBS. Confusing "approximating" with
"interpolating" is the number-one beginner mistake here.