Computer Graphics · Animation
Keyframe Reduction and the Error Metric That Decides It
How a dense sampled curve becomes a sparse key list, why the error must be measured against the reconstructed curve and not the original samples, and where per-channel reduction breaks a skeleton.
Motion capture and physically driven animation arrive as a value per frame per channel. A minute of capture at 120 samples per second across sixty joints with rotation, translation, and scale is a large quantity of numbers, most of which describe motion a cubic can reproduce within a fraction of a degree. Key reduction is the process of discarding keys while keeping the reconstruction within a stated tolerance, and the interesting content is not the discarding. It is the choice of tolerance, the place where the error is measured, and the ways a channel-by-channel reduction destroys relationships that only exist across channels.
The reduction problem stated precisely
Given samples $s_0 \dots s_{n-1}$ at times $t_0 \dots t_{n-1}$, choose a subset of indices to keep such that the curve reconstructed by the evaluator, sampling the kept keys with the channel’s interpolation mode, differs from the original by no more than $\epsilon$ everywhere. Minimizing the number of kept keys subject to that constraint is the objective, and the reconstructed curve is not a fixed function of the kept subset alone: with cubic interpolation the tangents at a kept key depend on its neighbours, so removing one key changes the shape of the segments on both sides of it.
That coupling is what separates this problem from polygon simplification. In Douglas-Peucker style simplification of a polyline, a removed vertex changes only the two segments that contained it, and the error can be computed locally from the chord. With cubic segments and automatic tangents, removal propagates: a key’s tangent is derived from the chord slopes to its neighbours, so deleting a key changes the tangent of the key before it and after it, which changes the shape of segments further away. The practical consequence is that a greedy scheme which removes one key at a time and re-evaluates only its own neighbourhood can accept a removal that pushes a segment three keys away out of tolerance. The fix is either to recompute the affected span before accepting, or to constrain tangents so that removal is local, which means storing tangent values in the file rather than deriving them.
/* Optimal key selection for one channel by dynamic programming.
err[i][j] is the maximum deviation of the segment from key i to key j,
precomputed incrementally; best[j] is the fewest keys up to j. */
for (int j = 1; j < n; j++) {
best[j] = INT_MAX;
for (int i = 0; i < j; i++) {
if (err[i][j] <= eps && best[i] + 1 < best[j]) {
best[j] = best[i] + 1;
prev[j] = i; /* segment from key i to key j */
}
}
}
/* Walk prev[] back from n-1 to recover the kept key indices. */
The dynamic program is exact for the constraint it encodes and costs $O(n^2)$ segment evaluations, which for a channel of a few thousand samples is a few million operations. The $O(n^2)$ is payable offline and not at load. The catch is that err[i][j] assumes the segment from i to j is evaluated with whatever tangents the final key set produces, and those tangents are only known once the neighbours are chosen. Practical implementations resolve this by fixing tangents from the original dense samples before reduction, or by iterating: reduce, re-derive tangents, re-check, and repeat until no segment exceeds tolerance. The iteration converges in a small number of passes because each pass removes keys and the corrections shrink.
Choosing an error metric that means something
A tolerance in value units is easy to state and hard to justify. A quaternion component error of 0.01 is not an angle; the angle it corresponds to depends on the other components, and near a half-turn rotation the same component error is a much larger angular error. The honest metric for a rotation channel is the angle of the relative rotation between original and reconstructed, which is $2\arccos|q_1 \cdot q_2|$ clipped to the valid range, and it is what a tolerance should be expressed in when the consumer is a deformation. For translation channels the metric can be distance in the joint’s frame, or better, distance in the space where it matters: a fingertip’s positional error under a small root translation error is the same magnitude, but a bone length error becomes a visible limb stretch.
A second choice is where in time the error is measured. Sampling only at the original sample times understates the error, because the reconstructed cubic can deviate most between the samples it was fit to, especially when the original signal has a sharp feature that fell between two samples. The safe approach is to evaluate at a finer grid than the source, at two to four substeps per original interval, and take the maximum. On playback at the source rate the between-sample deviation is invisible, which is why reduction tools that validate only at sample times appear to work and then produce a curve that pops when the clip is played at half speed or viewed in slow motion.
For skinning, the metric that actually bounds visual error is in the vertex positions, not the joint rotations. The relationship between them is the Jacobian of the deformation: an angular error $\delta\theta$ at a joint moves a vertex at distance $d$ from the joint by approximately $d \cdot \delta\theta$. A vertex on a long limb therefore amplifies error that is negligible at a nearby one, and a fixed angular tolerance across all joints allocates the budget wrong. The usual compromise is a per-joint angular tolerance scaled by the bone length below it, which keeps positional error roughly uniform; the meshes far from the skeleton are the ones that suffer when this is skipped.
Reducing a curve is only half of the size
Keys are not the only redundancy. Each key carries its value in 32-bit floats, and the value range for a rotation component is bounded by the unit constraint, so four components carry about the information of three. Quantizing each component to a fixed number of bits, and renormalizing after reconstruction, buys a factor without moving any key. The error budget splits between keys and bits, and the two compose; a reduction that spends the entire tolerance on curve shape leaves nothing for quantization and vice versa.
Times carry redundancy too, since they are monotonic and bounded by the clip duration. Storing the first time absolutely and subsequent times as deltas from the previous key keeps each delta in a small range, and a 16-bit delta covers spans of thousands of frames at frame-resolution. The constraint that makes this safe is that a delta must be representable: a gap longer than the maximum delta requires either a key inserted in the gap or a wider field. Reading such a file with a decoder that assumes uniform time deltas produces a channel whose keys drift progressively out of position, and the animation plays at the wrong speed while remaining superficially smooth.
The file format sets the boundary on what can be quantized. glTF 2.0 requires animation sampler accessors to hold floating-point data, so quantization of the values is an application-level encoding rather than something the container expresses; a tool that writes normalized integers into a sampler accessor produces a file that a conforming reader will reject or misread. Formats that carry their own curve representation, or engines that consume an internal cooked format, place the quantization in their own header where the reader knows to expect it. The distinction matters because the tolerance and bit depth are coupled to the decoder, not to the data.
Per-channel reduction breaks cross-channel invariants
A skeleton’s channels are not independent in the rendered result. Bone lengths are fixed by construction only if the translation channels of child joints are not animated; when a joint translates, its chain can stretch. Contact between a foot and the ground is an invariant that no single channel encodes: it is a relationship between the root translation, the hip rotation, the knee, and the ankle, and it holds exactly as long as each of those channels is exact.
Reducing each channel independently to its own tolerance allows those errors to add. Each channel stays inside its budget, and the sum of them at the end of the chain exceeds what the contact constraint permits, so a planted foot slides by a few millimetres per frame or sinks into the ground. The artifact is small and continuous, which makes it look like a physics or an authoring problem rather than a compression one. The mitigation is either a tighter tolerance on the channels that participate in a contact, or a post-reduction pass that evaluates the reduced pose at each sample time and measures the contact error, adding keys back where it exceeds a limit. That pass is an interval problem again: the keys to insert are where the accumulated error peaks, and they can be found by evaluating the whole reduced curve rather than by inspecting channels.
The same reasoning applies to joint chains that must maintain a rotation relationship, such as a hand whose fingers are posed to grip an object. Reducing the wrist and the fingers to independent tolerances changes the grip, and the object intersects the hand. A per-limb error budget, expressed as the maximum displacement of the end effector over the clip, is the smallest unit that captures these relationships.
What reduction costs at runtime
Sparse keys make evaluation less uniform. A channel with keys at irregular times requires a search, $O(\log n)$ per sample, where a dense per-frame channel could be indexed directly. That cost is small but it is not zero, and it interacts with the frame rate: a clip reduced to keys every eight frames is sampled eight times between keys, so the search result is reused; a clip played at a very high sampling rate or scrubbed randomly pays it every sample. The usual structure is a cached segment index per channel that is validated against the last queried time, which turns sequential playback into a compare and random access into a search.
Sparse keys also change how blending behaves, because two clips in a blend may have keys at different times. Blending is defined on values at a time, so the difference in key placement is invisible to the blend itself: each clip is evaluated at the shared time and the outputs are combined. The subtlety is that the tolerance of each clip is now a tolerance on a value that will be mixed, and the mixed result can exceed either input’s bound when the two errors point in opposite directions. Reducing both clips to half the desired final tolerance bounds the blend.
Interpolation modes interact with reduction in a way that is easy to get wrong. A step channel’s keys cannot be removed without changing which value holds over an interval; a reduction tool that treats it like a linear channel shifts the transition times. In the cubic case, storing explicit tangents makes removal local and the reduction tractable, at the cost of more numbers per key. And in the rotational case, the reduction must respect the sign convention of quaternion keys, because a sign flip between kept keys that was harmless in the dense form becomes a long-arc interpolation once the intermediate keys are gone.
References
- glTF 2.0 Specification, Animations — Khronos Group
- An Algorithm for the Reduction of Motion Capture Data — Lee, Shin and Kim, Pacific Graphics 1999
- Algorithm 19: Polygonal Approximation of Plane Curves — Ramer, Computer Graphics and Image Processing, 1972