You have captured a big pile of motion: an actor in a suit dotted with markers, wandering a studio for an afternoon — a walk here, a turn there, a jog, a stop, a look-around. It is gorgeous, human, real motion. But it is also fixed: each clip plays exactly the path the actor happened to take. Your game needs the character to walk to that door, then turn and jog to this waypoint — a route the actor never performed. How do you get new, controllable motion out of a finite library of old clips, without it ever looking synthetic?
The answer, from two landmark 2002 papers (Kovar, Gleicher & Pighin's Motion Graphs and Arikan & Forsyth's Interactive Motion Generation from Examples), is to stop thinking of the database as a list of clips and start thinking of it as a graph you can walk. Every frame the character ever performed becomes a place you might be; wherever two moments look similar enough, you build a bridge between them; and then synthesising motion becomes finding a path. This page builds that idea from the ground up, works a concrete pose-distance example, and shows how a graph search turns "walk to that door in three seconds" into an answer.
Lay all your captured clips end to end as strips of frames. A motion graph reinterprets those strips: the edges are pieces of original, untouched motion (a run of consecutive frames), and the nodes are the points between pieces where you are allowed to jump from one clip to another. A node is a choice point; an edge is a stretch of guaranteed-real motion you play through until the next choice.
The magic is that every edge is real captured motion. Nothing on an edge was invented — it is exactly what the actor did. The only synthetic moments are the short blended transitions at the nodes, and if we only ever place nodes where two frames genuinely match, even those are imperceptible. We get endless novel routes out of finite footage, all of it still looking human.
Below is a toy motion graph. Each labelled node is a frame where clips can meet; the plain arrows are the original clips (walk, jog, turn) playing forward through their frames; the highlighted arrow is a transition edge — a bridge discovered because the frame at its tail looked very like the frame at its head. A character controller lives on this graph: it plays along an edge, and at each node it may continue or take a transition, weaving the short clips into arbitrarily long, varied motion.
Read a route off it: enter the walk, at its end take the highlighted transition into the jog, run the jog, loop back through the turn — you have just produced a walk-then-jog-then-turn performance the actor never recorded in that order. Different constraints pick different walks through the same graph.
A transition is only allowed between two frames that are genuinely alike, so we need to measure
how alike two poses are. The workhorse is a pose distance: put the skeleton's joints as
3-D points and compare them. Write frame
But raw positions are in world space, so a walk heading north and an identical walk heading east would
look far apart just because they sit in different places and face different ways. That is wrong: pose
similarity should not care where the character is or which way it faces. So before
comparing, we align frame
Two refinements matter. First, we compare over a short window of frames rather than a
single instant, so the motions match in direction of travel, not just static pose — this is
what folds velocity into the metric. Second, the weights
Let us do the arithmetic with a cartoon 3-joint skeleton (hip, foot, hand) to see a threshold create an edge. Take two frames, already root-aligned so we can just subtract coordinates. Positions in metres:
| joint | frame A | frame B | squared diff |
|---|---|---|---|
| hip | (0.0, 1.0, 0.0) | (0.0, 1.0, 0.0) | |
| foot | (0.1, 0.0, 0.2) | (0.2, 0.0, 0.2) | |
| hand | (0.3, 1.2, 0.0) | (0.3, 1.2, 0.1) |
The hip matches exactly; the foot differs by
With a threshold of, say,
Now we have a graph whose walks are all valid motions. To make the character actually do something, we search the graph for the walk that best satisfies the user's request. Constraints come in several flavours:
Turn the request into a numeric cost — for "reach the door in 3 seconds", the cost of a
candidate walk is how far its endpoint lands from the door after
Because the graph encodes possibilities, not a single performance — it is the search's cost function that decides which walk you get. Feed in "amble roughly northward with no deadline" and the cheapest walk meanders through gentle walk-and-turn edges. Feed in "be at the exit in two seconds" and the very same edges are re-scored, now favouring long jog clips and punishing detours; the search returns a completely different route. One graph, one search algorithm, unlimited behaviours — you author the goal, and the pre-captured motion supplies the style. This separation of "what to do" (constraints) from "how it looks" (the database) is exactly why motion graphs powered a generation of game locomotion systems.
Two traps sink naive motion graphs. First: matching pose alone is not enough — you must match velocity too. Two frames can have nearly identical joint positions while one foot is swinging forward and the other backward; splice them and the foot visibly reverses, giving a jump or a foot-slide that blending only smears rather than cures. That is why the metric compares over a short window (so directions of motion must agree), not a single instant — connecting dissimilar frames looks broken even after the blend.
Second: a graph can be full of edges yet still trap the character in a dead end — a node from which no walk ever returns to the rich part of the graph, so the search gets stuck or the character freezes. The fix is pruning to strong connectivity: compute the largest strongly connected component (every node reachable from every other) and throw away everything outside it. Only then is every remaining node a safe place to be, with a way onward no matter what the user asks next. Skip this pruning and your beautiful graph will occasionally strand the character mid-stride.