You already know how a rig works: a skeleton is a tree of bones, each one a child of the last (a hand hangs off a forearm, which hangs off an upper arm, which hangs off a shoulder), and an animation clip is a recorded set of rotations, sampled many times a second, for every bone in that tree. Play the clip back and the whole skeleton moves exactly the way an animator posed it, frame by frame. That is enough for most animation - walking, idling, swinging a sword - but it breaks down the moment the world does something the animator could not predict ahead of time: a foot needs to land exactly on a rock that is not in the original level, a hand needs to grab a doorknob at a height that depends on the player's exact position, or a character needs to keep looking at a target that is moving. This chapter covers the two techniques that solve that: inverse kinematics (IK), which computes joint angles from a target instead of the other way around, and root motion, which lets the animation itself decide how far the character actually moves through the world.
We start with the difference between forward and inverse kinematics, build a real two-bone IK solver from scratch with the exact math (the same law of cosines idea from basic trigonometry, just pointed at a shoulder and an elbow instead of an abstract triangle), then look at the two standard ways to solve IK for longer chains. After that we cover three IK problems almost every third-person game solves in practice: feet on uneven ground, aiming and looking at a target, and reaching for a fixed point like a wall. The second half of the chapter is root motion: how a clip can carry its own movement data, when that beats moving a character in code, and how to combine the two so a root-motion clip still respects collisions.
Everything you have done with animation so far, without necessarily naming it, is forward kinematics (FK): you, or an animator, or the Animator component blending clips, sets the rotation of each joint directly, and the position of every bone below it in the hierarchy falls out automatically, because a child bone's world position is its parent's world position plus a rotated offset. Set the shoulder's rotation, then the elbow's, then the wrist's, and the hand ends up wherever that chain of rotations puts it. You never choose the hand's position directly - it is a result, not an input.
This is simple, fast, and exactly what keyframed animation already gives you for free: an animator poses the shoulder and elbow angle by angle, and the hand naturally ends up wherever a real hand attached to those bones would be. The problem shows up the moment you need the opposite: "keep this hand exactly on that doorknob" or "keep this foot exactly on that rock." The doorknob's position does not care what angles you picked - you need to work backward from where the hand must be to what angles put it there. That backward problem is inverse kinematics, and unlike FK it does not have one obvious answer.
Inverse kinematics (IK) flips the problem around: you pick a target - a position (and sometimes a direction) you want the end of a bone chain, the end effector, to reach - and a solver works backward to compute the joint angles that get it there.
Why is this harder than FK? Because in general there is not one answer, there are infinitely many. Stand in front of a doorknob and reach for it: your shoulder, elbow, and wrist can settle into more than one combination of angles that still puts your hand on the knob - raise your elbow a little and your shoulder compensates, and your hand does not move at all. Mathematically, a chain with many joints has more degrees of freedom (independent ways it can move) than the 3 numbers (x, y, z) needed to describe the target position, so the system is underdetermined - there are more unknowns than equations. A full-body character rig might have dozens of rotatable joints all trying to satisfy a handful of targets (two feet, two hands, a look-at direction), which is why production IK systems layer several specialized solvers together instead of solving "the whole skeleton" as one giant equation.
The good news: the single most common IK case in games - a two-segment limb like an arm (shoulder-elbow-hand) or a leg (hip-knee-foot) reaching for one target - has exactly one clean, closed-form (meaning an exact formula, not a step-by-step approximation) solution once you add one more piece of information about which way it should bend. That is two-bone IK, and it is worth understanding fully because the same triangle math shows up, in disguise, inside almost every other IK technique in this chapter.
TwoBoneIKConstraint (from the Animation Rigging package) implements internally.Picture an arm: a fixed shoulder, an elbow that bends, and a hand you want to place at some target point. The shoulder never moves (it is the root of this small chain). The two bone lengths - shoulder-to-elbow and elbow-to-hand - never change either; bones do not stretch. What changes every frame is only the target position, which is usually wherever the player's aim point, a foot-placement raycast, or a grabbed object happens to be right now.
Those three fixed pieces of information (two bone lengths, plus wherever the target currently is) always describe a triangle: one side is the upper bone, one side is the lower bone, and the third side is the straight-line distance from the shoulder directly to the target - a distance no real bone actually spans, but a useful imaginary line for the math.
Once you know all three side lengths of a triangle, plain trigonometry gives you every angle inside it - you do not need to guess, iterate, or search. That is exactly what makes two-bone IK a closed-form solution instead of the iterative solvers in sections 7 and 8: it computes the exact answer directly from a formula, every single frame, with no loop and no "getting closer over several tries."
D (distance from shoulder to target) changes every frame, but L1 and L2 (the actual bone lengths) should not. Compute L1 and L2 once, in Awake() or Start(), from the character's rest pose, and cache them - recomputing them every frame from the current, already-bent pose feeds the solver garbage the moment the arm is not perfectly straight.You met the law of cosines in the trigonometry chapter as the general version of the Pythagorean theorem for triangles that are not right triangles. For a triangle with sides a, b, c, where C is the interior angle opposite side c:
Apply that to the shoulder-elbow-target triangle from section 3, using its three known sides L1, L2, D. We need two angles: the elbow angle (the interior angle at E, between the upper and lower bone - this tells us how bent the arm is) and the shoulder angle (the interior angle at S, between the upper bone and the straight line to the target - this tells us how far the upper arm swings away from pointing straight at the target).
Solve the law of cosines for each angle by picking which side plays the role of "c" (the one opposite the angle you want):
Then elbowAngle = acos(...) and shoulderAngle = acos(...) (acos, "arc-cosine," is the inverse of cosine - it turns a cosine value back into an angle, the same idea as atan2 from the trigonometry chapter, just built for a different ratio). Two things worth noticing before writing any code:
D equals L1 + L2 exactly (the target is exactly as far away as the arm can fully reach), the elbow angle comes out to 180 degrees - a perfectly straight arm. That matches intuition: reaching for something exactly at your fingertip's maximum range means no bend at all.D is greater than L1 + L2, the target is unreachable - no triangle with those side lengths exists, and the formula above would take the arc-cosine of a number outside the range -1 to 1, which is undefined. Real code always clamps D to the reachable range before running the formula (shown in section 5) instead of letting that happen.Worked example: an upper arm of length L1 = 0.5, a forearm of length L2 = 0.4, and a target sitting exactly D = 0.7 units from the shoulder.
That elbow angle of about 101.5 degrees is the elbow's interior angle, not "how far it bent from straight" - a fully straight arm is 180 degrees, so this arm is bent about 78.5 degrees away from straight. Keep that distinction in mind: it trips people up the first time they wire this into a rig, because most animation rigs think in terms of "bend amount from rest," not "interior triangle angle."
Rather than working with raw angles and rig-specific bone axes (which vary from rig to rig and get confusing fast), the cleanest way to implement this is to compute positions directly: where the elbow should be, and where the target-clamped hand position should be. Any rig can then be told to point its bones at those positions, however that rig's convention wants it done.
The solver needs one more piece of information the pure triangle math does not give you: which direction the elbow should bend. Three fixed sides pin down a triangle's shape, but that triangle can still spin freely around the line from shoulder to target, like a hinge with no stop - picture your own elbow swinging in a full circle around the line from your shoulder to your hand while your hand stays perfectly still. Real elbows and knees do not do that; they bend toward one consistent side. That side is given by a pole vector, covered fully in section 6 - for now, treat it as a hint position that says "bend toward here."
using UnityEngine;
public static class TwoBoneIK
{
// root: shoulder / hip position (fixed, chain does not move this joint)
// target: where the tip should end up
// pole: a hint position that decides which way the joint bends
// lenUpper/lenLower: the two REST-POSE bone lengths, cached once and never
// recomputed from the current (already-bent) pose
// mid/tip: OUTPUT - the solved elbow/knee and hand/foot positions
public static void Solve(
Vector3 root, Vector3 target, Vector3 pole,
float lenUpper, float lenLower,
out Vector3 mid, out Vector3 tip)
{
Vector3 toTarget = target - root;
float rawDist = toTarget.magnitude;
// clamp to the reachable range so acos() never receives a value
// outside -1..1 (see section 4's "unreachable target" note)
float maxReach = lenUpper + lenLower;
float minReach = Mathf.Abs(lenUpper - lenLower);
float dist = Mathf.Clamp(rawDist, minReach + 0.0001f, maxReach - 0.0001f);
Vector3 dirToTarget = toTarget.normalized;
// law of cosines: angle at the ROOT, between the upper bone and
// the straight line to the (clamped) target
float cosRootAngle = (lenUpper * lenUpper + dist * dist - lenLower * lenLower)
/ (2f * lenUpper * dist);
float rootAngle = Mathf.Acos(Mathf.Clamp(cosRootAngle, -1f, 1f));
// axis to bend around: perpendicular to the plane made by the
// target direction and the pole direction (see section 6)
Vector3 dirToPole = (pole - root).normalized;
Vector3 bendAxis = Vector3.Cross(dirToTarget, dirToPole);
if (bendAxis.sqrMagnitude < 0.000001f)
bendAxis = Vector3.Cross(dirToTarget, Vector3.up); // fallback, rare
bendAxis.Normalize();
// rotate the "straight at target" direction by rootAngle around
// bendAxis to get the direction from root to the elbow/knee
Quaternion rot = Quaternion.AngleAxis(rootAngle * Mathf.Rad2Deg, bendAxis);
Vector3 dirToMid = rot * dirToTarget;
mid = root + dirToMid * lenUpper;
tip = root + dirToTarget * dist; // exactly lenLower away from 'mid' by construction
}
}
The last line is the payoff of doing the algebra in section 4 first: because dist, lenUpper, and lenLower already satisfy the law of cosines exactly, the point root + dirToTarget * dist is guaranteed to be exactly lenLower away from mid - the triangle closes perfectly, every frame, with no drift and no extra correction step.
rootAngle before building the rotation, or swap the two arguments to Vector3.Cross. Which sign is correct depends on your rig's own axis conventions, and getting it backward the first time you wire up a new rig is extremely common - it is a one-line fix once you notice it, not a sign your math is wrong.A minimal component that drives two real transforms with it:
using UnityEngine;
public class TwoBoneIKLimb : MonoBehaviour
{
public Transform root; // shoulder / hip - not moved by this script
public Transform mid; // elbow / knee
public Transform tip; // hand / foot
public Transform target;
public Transform pole;
float lenUpper, lenLower;
void Awake()
{
// cache the REST-POSE lengths once, before anything bends
lenUpper = Vector3.Distance(root.position, mid.position);
lenLower = Vector3.Distance(mid.position, tip.position);
}
void LateUpdate()
{
TwoBoneIK.Solve(root.position, target.position, pole.position,
lenUpper, lenLower, out Vector3 midPos, out Vector3 tipPos);
mid.position = midPos;
tip.position = tipPos;
// point each bone's local forward axis at its child - adjust
// to match whichever axis your rig treats as "along the bone"
root.rotation = Quaternion.LookRotation(midPos - root.position, pole.position - root.position);
mid.rotation = Quaternion.LookRotation(tipPos - midPos, pole.position - mid.position);
}
}
That last pair of LookRotation calls is doing real work: setting a bone's position does not automatically orient it - a bone is a stick with a length and an axis, and after moving mid and tip to new positions, root and mid also need their rotations updated so the visible mesh, skinned to these bones, actually stretches to follow instead of the bone position moving while the mesh stays twisted the old way. Notice this runs in LateUpdate, not Update: IK must always run after the Animator has finished posing the skeleton for the frame, or the IK result gets immediately overwritten by the next animation pose. That is the same reason follow-cameras run in LateUpdate, if you remember that from the camera chapter.
Update() instead of LateUpdate(). Unity's Animator updates transforms during its own internal timing, which is not guaranteed to run before an arbitrary Update() call on some other script. LateUpdate() is guaranteed to run after all Update() calls and after the Animator has applied the current frame's pose - exactly the ordering IK needs: pose first, then bend on top of it.Section 5 waved at this: three fixed side lengths only pin down a triangle's shape, not its rotation around the line from root to target. A pole vector (also called a pole target or an elbow/knee hint) is simply a position that tells the solver which side of that line the joint should bend toward. The solver picks the bend direction that gets the elbow or knee as close as possible to the pole position.
In practice the pole position is almost always a fixed offset a small distance in front of (for a knee) or behind (for an elbow) the character, not something that moves every frame like the main target does. A common setup: parent an empty GameObject to the character's hip or spine, offset it forward by roughly a knee's width, and use that as the pole for a leg's IK - it stays roughly where a real knee would naturally point no matter which direction the leg is currently reaching.
Two-bone IK has an exact formula because it only has two unknowns (two angles) and one triangle. A spine with six vertebrae, a tail with ten segments, or a tentacle rig has far more joints than that, and there is no single closed-form formula for an arbitrarily long chain. Instead, production code reaches for an iterative solver - one that does not compute the exact answer in one step, but instead takes repeated small steps that each get a little closer to the target, and stops once it is close enough (or after a fixed number of tries).
CCD (Cyclic Coordinate Descent) is the simplest iterative IK solver, and a good one to understand first because the idea fits in one sentence: working from the joint closest to the target end backward toward the root, rotate each joint by the amount that swings the chain's tip closer to the target, then repeat the whole pass a few times.
using UnityEngine;
public class CCDSolver : MonoBehaviour
{
public Transform[] joints; // joints[0] = root ... joints[last] = tip
public int iterations = 10;
public float tolerance = 0.01f;
public void Solve(Vector3 target)
{
Transform tip = joints[joints.Length - 1];
for (int pass = 0; pass < iterations; pass++)
{
if (Vector3.Distance(tip.position, target) < tolerance)
return; // close enough, stop early - no need to burn more passes
for (int i = joints.Length - 2; i >= 0; i--)
{
Transform joint = joints[i];
Vector3 toTip = tip.position - joint.position;
Vector3 toTarget = target - joint.position;
// the smallest rotation that swings 'toTip' onto 'toTarget'
Quaternion delta = Quaternion.FromToRotation(toTip, toTarget);
joint.rotation = delta * joint.rotation;
}
}
}
}
Quaternion.FromToRotation(a, b) returns exactly the rotation that takes direction a and points it at direction b - applying that rotation to the current joint immediately swings the whole rest of the chain (everything below it, including the tip) toward the target. CCD is cheap, simple to implement, and handles any chain length or joint-angle limits you bolt onto it, but it has a known quirk: because the joints nearest the tip get adjusted every single pass while the joints nearest the root only get a small say, CCD chains can visibly "curl" near the end effector instead of bending smoothly along their whole length, especially with a small iteration count.
FABRIK (Forward And Backward Reaching Inverse Kinematics) fixes CCD's curling problem with a different idea entirely: instead of rotating joints, it directly moves positions, back and forth along the chain, and only re-derives rotations from the final positions at the very end (exactly like section 5's two-bone solver did).
Each pass has two halves. The backward pass starts by snapping the tip straight onto the target - cheating, since that instantly breaks every bone length in the chain - then walks back toward the root, fixing one bone length at a time, always keeping each joint exactly the right distance from the joint after it. The forward pass then does the same thing in the other direction: snap the root back to its true fixed position, then walk toward the tip fixing bone lengths again. Because both passes always move a point exactly onto the line toward its neighbor, at the neighbor's already-correct distance, no bone length is ever violated once a pass finishes.
using UnityEngine;
public class FabrikSolver : MonoBehaviour
{
public Vector3[] points; // points[0] = root ... points[last] = tip
public float[] boneLengths; // boneLengths[i] = distance(points[i], points[i+1])
public int iterations = 10;
public float tolerance = 0.01f;
public void Solve(Vector3 target)
{
Vector3 rootPos = points[0];
float totalLength = 0f;
for (int i = 0; i < boneLengths.Length; i++) totalLength += boneLengths[i];
// target out of reach: just stretch the whole chain straight at it
if (Vector3.Distance(rootPos, target) > totalLength)
{
for (int i = 0; i < points.Length - 1; i++)
{
float r = Vector3.Distance(target, points[i]);
float lambda = boneLengths[i] / r;
points[i + 1] = Vector3.Lerp(points[i], target, lambda);
}
return;
}
for (int pass = 0; pass < iterations; pass++)
{
if (Vector3.Distance(points[points.Length - 1], target) < tolerance)
break;
// backward pass: target -> root
points[points.Length - 1] = target;
for (int i = points.Length - 2; i >= 0; i--)
{
float r = Vector3.Distance(points[i + 1], points[i]);
float lambda = boneLengths[i] / r;
points[i] = Vector3.Lerp(points[i + 1], points[i], lambda);
}
// forward pass: root -> tip
points[0] = rootPos;
for (int i = 0; i < points.Length - 1; i++)
{
float r = Vector3.Distance(points[i + 1], points[i]);
float lambda = boneLengths[i] / r;
points[i + 1] = Vector3.Lerp(points[i], points[i + 1], lambda);
}
}
}
}
Vector3.Lerp(a, b, lambda) here does the same "move partway from a to b" job as everywhere else you have used it, just with lambda chosen so that partway point lands at exactly boneLengths[i] from its neighbor rather than some arbitrary blend fraction. FABRIK usually converges in noticeably fewer passes than CCD and bends smoothly along the whole chain instead of curling near the tip, which is why most modern engines, including Unity's own Animation Rigging package for its multi-bone "Chain IK" constraint, use FABRIK-style solvers for chains longer than two bones.
Here is the problem in one picture: a walk animation was made assuming flat ground, so every frame it places each foot at a specific height relative to the hips. Put that same character on a slope or a staircase, and the animation has no idea the ground moved - feet either float above the surface or sink into it, depending on which way the real ground departs from flat.
The fix follows directly from the diagram: for each foot, fire a raycast straight down from a point a little above where the animation currently thinks the ankle should be, find where it actually hits the ground, and feed that hit point into the foot's IK target instead of trusting the animation's own height. The upper leg and lower leg then bend by exactly however much is needed to still reach that corrected point - which is precisely what the two-bone solver from section 5 computes.
Unity's Humanoid rig has a built-in two-bone IK system for exactly this, driven through Animator.SetIKPosition and friends inside a special callback, OnAnimatorIK, which only fires if the Animator Controller's layer has its "IK Pass" checkbox enabled:
using UnityEngine;
public class FootIK : MonoBehaviour
{
public Animator animator;
public LayerMask groundMask;
public float raycastHeight = 0.5f; // start the ray this far above the foot
public float raycastDistance = 1.5f;
public float footSoleOffset = 0.05f; // keeps the sole from clipping into the ground
void OnAnimatorIK(int layerIndex)
{
PlaceFoot(AvatarIKGoal.LeftFoot);
PlaceFoot(AvatarIKGoal.RightFoot);
}
void PlaceFoot(AvatarIKGoal foot)
{
Vector3 animatedPos = animator.GetIKPosition(foot);
Vector3 rayOrigin = animatedPos + Vector3.up * raycastHeight;
if (Physics.Raycast(rayOrigin, Vector3.down, out RaycastHit hit, raycastDistance, groundMask))
{
Vector3 targetPos = hit.point + Vector3.up * footSoleOffset;
Quaternion tiltToSurface = Quaternion.FromToRotation(Vector3.up, hit.normal);
animator.SetIKPositionWeight(foot, 1f);
animator.SetIKRotationWeight(foot, 1f);
animator.SetIKPosition(foot, targetPos);
animator.SetIKRotation(foot, tiltToSurface * animator.GetIKRotation(foot));
}
else
{
// no ground found under this foot (e.g. stepping off a ledge):
// fade IK out and let the plain animation play
animator.SetIKPositionWeight(foot, 0f);
animator.SetIKRotationWeight(foot, 0f);
}
}
}
Two Unity-specific pieces are doing the real work here. animator.GetIKPosition(foot) asks "where did the currently playing animation clip want this foot, before any IK touches it?" - that is the natural raycast starting point, because it already accounts for whatever pose (mid-stride, weight-shifted, whatever) the clip is in right now. SetIKPositionWeight and SetIKRotationWeight (0 to 1) blend between "ignore IK entirely, trust the animation" (0) and "fully trust the IK position" (1) - fading this smoothly instead of snapping between 0 and 1 is what stops a foot from visibly popping the instant it steps off the edge of detected ground.
One more detail matters for anything steeper than a gentle slope: if one foot needs to reach down noticeably farther than the animation expects (stepping down a tall stair, for instance), the leg can run out of length before the foot reaches its raycast target - the two-bone solver in section 5 already clamps to the reachable range, so the leg simply straightens out and stops, and the foot floats above the target instead of reaching it. The standard fix is to lower the whole hip by roughly the largest shortfall between any animated foot height and its real IK target, so every leg gets enough extra reach:
float ComputeHipDrop(Animator animator, float leftTargetY, float rightTargetY)
{
float leftDrop = Mathf.Max(0f, animator.GetIKPosition(AvatarIKGoal.LeftFoot).y - leftTargetY);
float rightDrop = Mathf.Max(0f, animator.GetIKPosition(AvatarIKGoal.RightFoot).y - rightTargetY);
return Mathf.Max(leftDrop, rightDrop);
}
// inside OnAnimatorIK, after computing both raycast targets' Y heights:
float hipDrop = ComputeHipDrop(animator, leftTargetY, rightTargetY);
animator.bodyPosition -= Vector3.up * hipDrop;
This is exactly the same reasoning as the leg-reach clamp from section 5, just applied one level up: instead of letting an overextended leg go perfectly straight and visibly "run out," you move the whole body down slightly so neither leg ever needs to reach past its natural length in the first place.
The same trick - take an animated pose, then bend a small part of it toward a target using IK - applies just as well to looking at something as it does to placing a foot. A character whose eyes should track a nearby item, or whose upper body should aim a weapon at a crosshair while the legs keep running their normal locomotion animation underneath, is solving the exact same category of problem.
Unity's Humanoid rig ships a ready-made look-at IK for exactly the "track a point with the head/eyes/spine" case:
using UnityEngine;
public class LookAtIK : MonoBehaviour
{
public Animator animator;
public Transform lookTarget;
[Range(0f, 1f)] public float lookWeight = 0.7f;
void OnAnimatorIK(int layerIndex)
{
if (lookTarget == null)
{
animator.SetLookAtWeight(0f);
return;
}
animator.SetLookAtWeight(lookWeight);
animator.SetLookAtPosition(lookTarget.position);
}
}
Internally this spreads the look rotation across several bones at once (eyes, head, and a little of the spine) rather than snapping the head alone to face the target, which is why lookWeight below 1 still reads as natural - a real person glancing at something rarely turns only their head to the maximum angle, they rotate the whole upper body a little too.
Aiming a weapon needs the same idea but usually without a built-in helper, because how much of the aim should come from the spine versus the arms is very game-specific. A common approach: compute the rotation that would perfectly aim at the target, then Slerp only partway there and apply it to a spine or chest bone, layered on top of whatever the locomotion animation is already doing to that bone:
public Transform spineBone;
public Transform aimTarget;
[Range(0f, 1f)] public float aimWeight = 0.6f;
void LateUpdate()
{
Vector3 aimDir = (aimTarget.position - spineBone.position).normalized;
Quaternion fullAim = Quaternion.LookRotation(aimDir, Vector3.up);
// blend between "whatever locomotion already posed this bone to"
// and "fully aimed", instead of overwriting it outright
spineBone.rotation = Quaternion.Slerp(spineBone.rotation, fullAim, aimWeight);
}
You already met Slerp in the rotation chapter as the correct way to blend between two orientations along the shortest arc; here it doubles as a weight-blend between "pure animation" and "pure aim," the same job lookWeight and the IK position weights did earlier in this chapter. Nearly every practical IK use in this section reduces to the same pattern: compute a fully-solved IK result, then blend it against the underlying animation by some 0-to-1 weight instead of replacing it outright.
The last common case is a character's hand needing to land on a specific fixed point - pressing a button, leaning a hand flat against a wall while walking past it, gripping a ladder rung. This is not a new technique at all: it is exactly the two-bone solver from section 5, with target set to that fixed point (found however makes sense for the situation - a designer-placed marker, or a short raycast forward from the hand toward the wall) and its weight faded in as the character gets close enough for the reach to look natural, and faded back out once they walk away.
Everything so far in this chapter bends an already-playing animation to reach a target. Root motion is a different topic entirely: it is about where the whole character moves through the world, not how a limb bends within that pose.
When an animator creates a run cycle, the hips (the animation's root bone, usually literally named something like "Hips" or "Pelvis") do not just bob up and down in place - they also translate forward, exactly matching however far a real runner's hips travel during that stride. That forward translation is root motion: movement data baked directly into the animation clip itself, frame by frame, alongside all the normal joint rotations.
Unity reads that delta automatically every frame through two Animator properties, deltaPosition and deltaRotation - "how far did the root move, and how much did it turn, since last frame, according to the clip." Whether that delta actually gets applied to the GameObject's real transform is controlled by one flag:
using UnityEngine;
[RequireComponent(typeof(Animator))]
public class RootMotionMover : MonoBehaviour
{
Animator animator;
void Awake()
{
animator = GetComponent<Animator>();
animator.applyRootMotion = true;
}
// Unity calls this automatically, once per frame, right after the
// Animator finishes evaluating the current pose - but ONLY while
// applyRootMotion is true. This is where root motion actually applies.
void OnAnimatorMove()
{
// this is literally what Unity already does for you by default
// when applyRootMotion = true and you do NOT override OnAnimatorMove:
transform.position += animator.deltaPosition;
transform.rotation *= animator.deltaRotation;
}
}
With applyRootMotion = true and no custom OnAnimatorMove, Unity performs exactly that assignment for you automatically. The moment you write your own OnAnimatorMove, you take over - Unity still computes deltaPosition/deltaRotation from the clip every frame, but it is now entirely up to your code what, if anything, to do with them. That hook is exactly what lets root motion cooperate with collision, covered in section 12.
deltaPosition instead, which is real root motion). A clip authored for root motion in Maya or Blender needs this setting to actually match on import, or the character will not move even with applyRootMotion = true.The other option, which you already used throughout the character controller chapter without needing any of this: keep the animation clip in place (no net translation baked into the hip curve - the import setting from the tip above set to "Bake Into Pose") and move the character purely with code, using a hand-picked speed value fed into controller.Move() or rb.velocity exactly as you already know how to do.
Neither column is "correct" in general, the same way Rigidbody vs CharacterController was not a right-or-wrong choice back in the character controller chapter. Big-budget third-person action games (Souls-likes, most HoYoverse-style action RPGs) lean heavily on root motion specifically because it makes every attack, dodge, and heavy-footed turn feel exactly as weighty as the animator intended, frame for frame. Fast, responsive genres - platformers, arena shooters, anything where a player needs to feel input latency measured in single frames - usually lean code-driven, because root motion's "wait for the clip" quality works against split-second control.
The version in section 11 has a real problem: transform.position += animator.deltaPosition moves the character in a straight line with zero regard for walls, floors, or slopes, because it never goes through any collision system at all. The fix is exactly the hook OnAnimatorMove exists for: instead of touching transform directly, hand the clip's own delta to a CharacterController, the same component from the character controller chapter, so it gets the same collision handling as any code-driven move:
using UnityEngine;
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(CharacterController))]
public class RootMotionController : MonoBehaviour
{
Animator animator;
CharacterController controller;
float verticalVelocity;
void Awake()
{
animator = GetComponent<Animator>();
controller = GetComponent<CharacterController>();
animator.applyRootMotion = true;
}
void OnAnimatorMove()
{
Vector3 motion = animator.deltaPosition;
// gravity is still ours to add - root motion clips normally only
// carry horizontal locomotion, not falling
if (controller.isGrounded && verticalVelocity < 0f)
verticalVelocity = -2f;
verticalVelocity += Physics.gravity.y * Time.deltaTime;
motion.y = verticalVelocity * Time.deltaTime;
controller.Move(motion); // now respects walls, slopes, steps
transform.rotation *= animator.deltaRotation;
}
}
Notice this is not an either/or against everything earlier in the chapter: root motion decides how far the character moves each frame, and the IK techniques from sections 5 through 10 still run afterward (in LateUpdate, as always) to fix up feet and aim on top of wherever root motion just put the character. A root-motion walk cycle combined with foot IK is extremely common - root motion gets the overall pacing and weight right, foot IK then nudges each foot the last few centimeters onto whatever the ground actually is at that exact spot, something no amount of authored root motion could predict in advance.
animator.deltaPosition for forward movement, but also driving the Animator's speed parameter from a separate hand-tuned value used only to pick blend tree weights). If the blend tree's chosen playback speed does not match how far the clip's own root curve actually travels per second, the character's legs and its actual movement speed drift apart, and you get visible foot sliding again - the exact problem root motion exists to prevent. Keep one value as the single source of truth (usually player input speed feeding the blend tree) and let root motion's own baked distance follow whatever the resulting blended clip produces, rather than fighting it with a second, independent speed number.Animator.deltaPosition/deltaRotation.CharacterController) instead of letting it move transform directly.L1 = 0.6, lower bone length L2 = 0.5, and this frame's foot IK target sits exactly D = 0.9 units from the hip. Using the two law-of-cosines formulas from section 4, compute cos(elbowAngle) and elbowAngle in degrees, then cos(rootAngle) (the hip-side angle) and rootAngle in degrees.cos(elbowAngle) = (L1^2 + L2^2 - D^2) / (2*L1*L2)
= (0.36 + 0.25 - 0.81) / (2*0.6*0.5)
= -0.20 / 0.6 = -0.3333
elbowAngle = acos(-0.3333) = 109.5 degrees
cos(rootAngle) = (L1^2 + D^2 - L2^2) / (2*L1*D)
= (0.36 + 0.81 - 0.25) / (2*0.6*0.9)
= 0.92 / 1.08 = 0.8519
rootAngle = acos(0.8519) = 31.6 degrees
Sanity check: the three interior angles of any triangle add up to 180 degrees. The third angle (at the target point) is 180 - 109.5 - 31.6 = 38.9 degrees - a valid, non-negative angle, so these numbers describe a real, reachable pose.
L1 = 0.6, L2 = 0.5), but this time the raw target distance is D = 1.4 units from the hip. Is this target reachable? If not, what clamped distance does the solver from section 5 actually use, and what do elbowAngle and rootAngle come out to at that clamped distance? Describe in one sentence what the leg visually looks like in this case.Maximum reach is L1 + L2 = 1.1. The raw target distance of 1.4 is well past that, so the target is not reachable - the solver clamps D down to (essentially) maxReach = 1.1 (section 5's code subtracts a tiny epsilon so acos never receives exactly -1 or 1, but using 1.1 exactly keeps the hand math clean):
cos(elbowAngle) = (0.36 + 0.25 - 1.21) / 0.6 = -0.6/0.6 = -1.0
elbowAngle = acos(-1.0) = 180 degrees
cos(rootAngle) = (0.36 + 1.21 - 0.25) / (2*0.6*1.1) = 1.32/1.32 = 1.0
rootAngle = acos(1.0) = 0 degrees
An elbow angle of 180 degrees means the leg is perfectly straight, and a root angle of 0 degrees means the hip points directly at the (clamped) target with no swing at all. Visually: the leg fully extends and points straight at the target, but the foot stops short of actually reaching it, since the real target is 1.4 units away and the leg can only physically span 1.1.
z) displacement in each 0.2-second interval of its 1.2-second loop: 0.16, 0.28, 0.32, 0.32, 0.24, 0.12 meters. (a) What is the total distance traveled over one full loop? (b) What constant forward speed would a code-driven, in-place version of this character need, to cover the same total distance over the same 1.2-second loop? (c) Even with that speed matched exactly, why might a careful player still be able to feel a difference between the root-motion version and the constant-speed code-driven version?(a) Total distance is the sum of all six intervals: 0.16 + 0.28 + 0.32 + 0.32 + 0.24 + 0.12 = 1.44 meters per loop.
(b) Constant speed = total distance / total time = 1.44 / 1.2 = 1.2 meters per second.
(c) The root-motion clip does not move at a constant 1.2 m/s within the loop - it speeds up through the middle of the stride (up to 0.32m per 0.2s interval, or 1.6 m/s) and slows down near the contact poses at the start and end (0.16m and 0.12m per interval, or 0.8 and 0.6 m/s). A constant-speed in-place mover reproduces the correct total distance per loop, but loses that within-stride speed variation entirely, so the character's legs visually push off and land at moments that no longer quite match how fast the body is actually traveling at that instant - a subtle version of the exact foot-sliding problem root motion exists to solve, just averaged out over the whole stride instead of being obviously wrong every frame.