Free-Form Deformation

You have a dolphin. It is a beautiful mesh — forty thousand vertices, every scale and fin modelled by hand. Now the director wants it to squash as it launches out of the water and stretch as it arcs through the air. You are absolutely not going to drag forty thousand vertices around by hand. So instead you drop the whole dolphin inside an invisible rubbery box — a coarse lattice of, say, 4\times4\times4 handles — and you bend the box. The dolphin, riding along inside, bends with it. Squash the box top down and the dolphin squashes; pinch one corner and the nearest fin curls. You edited sixty-four handles and forty thousand vertices came along for free.

This is Free-Form Deformation (FFD), introduced by Thomas Sederberg and Scott Parry in 1986. Its one big idea is startling the first time you meet it: you do not deform the object at all — you deform the space the object sits in, and the object simply reads its new position out of that warped space. This page builds that idea from a Bézier curve up to a Bézier volume, works a one-dimensional slice by hand, and lets you bend a lattice with a slider.

From a Bézier curve to a Bézier volume

A Bézier curve takes one parameter s\in[0,1] and blends a row of control points with the Bernstein weights. A Bézier volume does the same trick in three parameters at once. Lay a grid of control points P_{ijk} — a lattice — around the object, and give every point of the enclosed space three local coordinates (s,t,u)\in[0,1]^3 telling you how far along the box's three edges it lies. The warped position of that point is a triple Bernstein blend:

Read that formula slowly, because it hides the whole magic. The local coordinates (s,t,u) are computed once, from the object's rest pose, and then frozen. After that, animation is nothing but moving the P_{ijk} and re-running the sum. Leave the control points in their original grid positions and the formula reproduces X exactly — the undeformed identity. Nudge one control point and every vertex whose blend touches it slides smoothly to follow.

Why a coarse box can bend a fine mesh

Here is the property that makes FFD indispensable. The deformation is a smooth function of space — Bernstein polynomials are infinitely differentiable — so whatever mesh you drop inside is warped by the very same smooth map. The lattice knows nothing about how many vertices the object has; it only warps points. Feed it a ten-vertex proxy or a ten-million-vertex film asset and both bend identically and smoothly.

That decoupling is the point. A modeller sculpts detail once at full resolution; an animator shapes motion with a handful of lattice handles. The two never fight over vertex counts.

See it move: a one-dimensional slice

A full trivariate volume is hard to draw on a page, so collapse it to a single edge — a row of four control points, a cubic Bézier "lattice" with just the s parameter. The faint straight line is the undeformed row of embedded vertices. The angular cage is the control polygon — the lattice you actually grab. The bold curve is where those vertices land after the deformation: the trivariate blend, here X_{\text{ffd}}(s)=\sum_i B_i^{3}(s)\,P_i. Slide the handle to lift the two middle control points and watch the whole embedded row bow smoothly upward — no vertex was touched directly; the space they live in was bent.

Notice two things. The bold curve is smoother than the cage — the sharp corners of the control polygon are rounded off by the Bernstein blend, which is exactly the smoothness that lets a jagged, coarse lattice produce a graceful bend. And the ends stay pinned: the outermost control points did not move, so the vertices near s=0 and s=1 barely budge. That is how you deform a limb while keeping the shoulder and the hand welded in place.

Worked example: bending a row by hand

Take four control points along one lattice edge at s = 0,\tfrac13,\tfrac23,1, initially with heights P = (0,0,0,0) — a flat, undeformed row. A vertex embedded at local coordinate s=\tfrac12 evaluates to the cubic Bézier blend

X_{\text{ffd}}(\tfrac12) = B_0^3\,P_0 + B_1^3\,P_1 + B_2^3\,P_2 + B_3^3\,P_3,\qquad B^3(\tfrac12)=\left(\tfrac18,\tfrac38,\tfrac38,\tfrac18\right),

which gives 0 — flat in, flat out, the identity. Now deform: lift the two middle handles to P=(0,1,1,0). The same vertex now lands at

X_{\text{ffd}}(\tfrac12) = \tfrac18(0) + \tfrac38(1) + \tfrac38(1) + \tfrac18(0) = \tfrac{3}{4}.

The midpoint rose by 0.75 even though we lifted the handles by 1 — the blend spreads the influence, which is why the bend looks soft rather than tent-like. Check the endpoints: at s=0 the weights are (1,0,0,0) so X_{\text{ffd}}=P_0=0, and likewise 0 at s=1. Pinned ends, lifted middle: a clean, art-directable bow from moving two numbers.

Where FFD sits in the rig

FFD is a deformer — one stage in a stack that carries a rest mesh to its final deformed shape. It plays two roles. Applied after skinning, it is a corrective / art-direction layer: squash-and-stretch on a jumping character, a broad "make the belly rounder" note, a stylised smear on a fast action — shape changes the joint hierarchy could never express. Applied before skinning, it can reshape the rest pose itself, letting one skeleton drive many silhouettes. Either way the lattice is small, animatable, and keyframeable just like any other channel.

Absolutely — the "trivariate Bézier volume" is just one choice of blending function, and the idea generalises the moment you swap it out. Replace the Bézier basis with a B-spline volume and you get local control: moving one handle only affects nearby cells, so a big lattice stays cheap to edit. Coons and Griessmair extended FFD to non-parallelepiped lattices; Coquillart's Extended FFD (EFFD) lets the lattice itself be an arbitrary shape (a cylinder around an arm, say) for more natural bends. Later work drops the grid entirely and drives the warp from scattered handles or a cage of arbitrary topology (cage-based / harmonic coordinates). All of them share FFD's founding move: don't push the vertices, warp the space and let the vertices ride.

The single most common misconception is to think of FFD as "grabbing the nearby vertices". It does not know your vertices exist. It warps a continuous region of space, and vertices merely report where that space carried them. Two consequences bite beginners:

Vertices in the same lattice cell move together. Two points that are far apart on the surface but fall inside the same coarse cell get almost the same displacement — so a lattice too coarse for the motion will drag a leg and a tail as one lump. The fix is not to "select fewer vertices" (there is no selection) but to add lattice resolution: more control points means smaller cells and finer, more local control. Conversely, a lattice that is too coarse simply cannot represent a sharp local wrinkle — the deformation it produces is only ever as detailed as its control grid, no matter how dense the mesh inside. Match the lattice resolution to the motion you need, not to the polygon count of the model.