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.

Two facts fall straight out of this recursion and define everything B-splines are good for:

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:

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)} .

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:

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.