Blend Trees and State Machines

A character in a game has no fixed timeline. One frame she is standing still; the next the player shoves the stick forward and she must walk, then run, then jam the button and leap. There is no animator sitting behind the console re-timing curves in real time — so the engine needs a small, cheap machine that watches a handful of numbers (speed, "is jump pressed?", "is grounded?") and, sixty times a second, decides which clips to sample and how much of each to mix. That machine is the animation-control layer, and it is built from two ideas that fit together like gears: animation state machines and blend trees.

A state machine answers "which behaviour are we in?" — idle, walk, jump — and how to slide between them. A blend tree answers "inside this behaviour, how do the clips mix?" — 40% walk, 60% run, right now. This page builds both, does the arithmetic of a speed blend by hand, and shows the one bug that ruins them: clips whose feet are out of step.

The animation state machine (ASM)

Picture a graph. Each node is a state — and a state is just "play this thing": a single clip (Idle, Jump), or a whole sub-graph (a Locomotion state that is itself a blend tree of walk and run). Each edge is a transition, and a transition carries three things: a condition that fires it, a blend duration over which the old state cross-fades into the new one, and a set of rules about when it is allowed to happen.

Two transition rules do most of the work. Exit time says "don't leave until the current clip has played to (say) 90% of its loop" — you use it so a footstep or an attack swing finishes cleanly instead of snapping mid-stride. Interruption says whether an in-progress transition can itself be cut short by a higher-priority one — you want a Hit reaction to interrupt a lazy Idle→Walk fade, but you do not want a jitter on the speed input to keep re-triggering Walk↔Run every frame.

Blend trees: mixing clips by a continuous parameter

A state machine is discrete — you are in walk or run. But real locomotion is a continuum: at 2.7 m/s you are neither purely walking nor purely running, you are somewhere between. A blend tree takes one or more continuous parameters and produces a weighted mix of clips whose weights sum to one.

The simplest is a 1D blend space. Place clips along a line by the value of a single parameter — say walk anchored at 1.5 m/s and run at 4 m/s — and for a query speed the tree linearly interpolates between the two neighbouring clips. It is the very same interpolation you use for numbers, applied to whole poses: blend joint by joint.

A 2D blend space spreads clips across a plane, most often movement direction × speed: forward, back, and the two strafes at the compass points, with a jog and a sprint further out. The query point — where the stick is pointing, how hard — lands somewhere inside, and the engine hands out weights to the surrounding clips. Common schemes are barycentric weights (the point sits inside a triangle of the three nearest clips) or a gradient band that falls off with distance; either way, the weights are non-negative and sum to one.

See it: a 2D blend space

Four clips sit at the corners of a movement square: forward vs back on the vertical axis, left vs right strafe on the horizontal. The dark dot is the blend point set by the two sliders (how much sideways, how much forward). Its position hands each corner clip a weight by bilinear interpolation — the fraction of the opposite rectangle's area — and the four always sum to 1. Slide it into a corner and that clip takes all the weight; park it dead centre and every clip gets 0.25.

The pose you finally send to the skin is \text{pose} = \sum_i w_i \,\text{clip}_i, \qquad \sum_i w_i = 1, the same weighted average taken independently on every joint's transform. Those blended joint transforms are exactly what the skinning stage consumes to deform the mesh — the control layer's whole job is to produce, each frame, one clean skeleton pose for skinning to eat.

Worked example: a 1D speed blend at 3 m/s

Take a 1D blend between two clips: walk anchored at v_\text{walk} = 1.5 m/s and run at v_\text{run} = 4.0 m/s. The character is currently moving at v = 3.0 m/s. What mix do we play?

Linear interpolation gives the run weight as the fraction of the way from walk to run: w_\text{run} = \frac{v - v_\text{walk}}{v_\text{run} - v_\text{walk}} = \frac{3.0 - 1.5}{4.0 - 1.5} = \frac{1.5}{2.5} = 0.6, and since the weights sum to one, w_\text{walk} = 1 - 0.6 = 0.4. So the frame's pose is 0.4\,\text{walk} + 0.6\,\text{run}, blended joint by joint. Nudge the speed to 4 and w_\text{run} \to 1; drop it to 1.5 and it is pure walk.

But there is a subtlety that the weight alone doesn't capture. If we sample the walk clip at its frame 7 and the run clip at its frame 20, their feet may be in totally different parts of the stride. Before blending, the engine phase-syncs the clips: it treats each loop as a normalised phase \phi \in [0,1) and samples both clips at the same \phi, so the left foot is planting in both at once. Only then does the 0.4 / 0.6 mix produce a clean stride instead of a mush.

Layers and masks: two things at once

A character often needs to do two unrelated things simultaneously — walk with the legs while the upper body waves or reloads. You get this with layers. A second animation layer runs its own state machine, but a mask (a per-bone weight, usually 0 or 1) restricts it to a subset of the skeleton: the wave layer has weight 1 on the spine-and-arms bones and 0 on the legs, so it overrides only the top half and lets the locomotion layer own the legs.

Per-bone weights need not be a hard 0/1 either: feathering the mask weight down across the spine bones blends the boundary so the waving torso doesn't snap rigidly onto the walking hips.

What it costs at runtime

The reason this whole scheme is the industry default is that it is astonishingly cheap. Per frame a blend node samples only its active clips — a 2D blend usually touches three or four, not the dozen in the space — interpolating each sampled joint transform, then takes a weighted average. That is a few pose evaluations plus one blend per bone: a handful of multiply-adds per joint, well under a millisecond for a normal skeleton. No solving, no simulation — just sampling stored curves and mixing them, which is why a crowd of hundreds of characters can each run its own state machine in real time.

In a 2D blend space the three nearest clips form a triangle around the query point, and the natural weights are its barycentric coordinates — the areas of the three sub-triangles you get by joining the point to the corners, each divided by the whole area. They are automatically non-negative inside the triangle and sum to one, which is exactly the "convex combination" property a pose blend needs (weights outside [0,1] would extrapolate poses into contorted, un-authored shapes). It is the same barycentric idea a renderer uses to interpolate colour across a triangle — here it interpolates whole skeletons instead of pixels.

The most common blend-tree bug is foot sliding — the character glides as if on ice, or the feet stutter and jitter. Almost always the cause is misaligned foot phase: you are averaging a walk clip in which the left foot is planted with a run clip in which the left foot is in the air. The blend puts the foot at some impossible in-between height, and because the two clips loop at different rates the mismatch drifts, so the plant point slides along the ground.

The fix is that every clip in a blend space must be phase-synchronised: authored (or retimed) so that the same normalised phase \phi means the same stride event — left-foot-down at \phi = 0, right-foot-down at \phi = 0.5 — in all of them. Engines enforce this with phase matching (a "sync group" that drives every clip in the blend from one shared phase clock, stretching each clip's playback so its footfalls line up). Blend the weights all you like; just never blend clips whose feet disagree about where they are.