Home Games Shader Sandbox

Game Dev Mechanics: Inverse Kinematics — How It Works

FABRIK IK Solver
Root (fixed)
Joints
End effector
Target
Move mouse or touch to control target • Watch FABRIK solve in real time

Move a character's hand to pick up an item. Aim a turret at a moving enemy. Make a spider's eight legs conform to uneven terrain. All of these require solving the same problem: given a target position, how do we automatically calculate the joint angles of a connected chain so its tip reaches that target? This is Inverse Kinematics — one of the most widely-used algorithms in game development and character animation.

Forward Kinematics vs. Inverse Kinematics

To understand inverse kinematics, we first need to understand its counterpart: forward kinematics (FK).

In forward kinematics, you control a chain of joints by explicitly setting each joint's rotation angle. Starting from the root joint (say, the shoulder), you rotate by angle $\theta_1$, then from the elbow you rotate by $\theta_2$, and so on down the chain. The position of the end effector — the hand, claw, or tip — is a consequence of those angle choices.

For a 2D chain of segments with lengths $l_1, l_2, \ldots, l_n$ and cumulative angles, the end effector position is:

$$\vec{p}_{end} = \sum_{i=1}^{n} l_i \begin{pmatrix} \cos(\phi_i) \\ \sin(\phi_i) \end{pmatrix}, \quad \text{where } \phi_i = \sum_{j=1}^{i} \theta_j$$

This is straightforward to compute, but awkward for game developers. Who wants to manually dial in shoulder and elbow angles just to make a hand reach a door handle? We want to specify the target position and have the system determine the joint angles automatically — that is inverse kinematics.

Mathematically, IK is the inverse problem: given $\vec{p}_{target}$, find angles $\theta_1, \ldots, \theta_n$ such that $\vec{p}_{end} = \vec{p}_{target}$. As anyone who has wrestled with nonlinear equations knows, inverses are rarely trivial.

Why IK Is Hard

For a single two-segment arm in 2D, IK has a clean analytical solution using the law of cosines. Given segment lengths $l_1$ and $l_2$, and distance $d$ from root to target:

$$\cos(\theta_2) = \frac{d^2 - l_1^2 - l_2^2}{2 l_1 l_2}$$

This directly yields the elbow bend angle. But the moment you add a third segment — let alone a full humanoid skeleton or a six-legged insect — the system becomes massively underdetermined. There are infinitely many valid joint configurations that place the end effector at the same target. A human arm can touch any reachable point in countless ways depending on elbow orientation, wrist rotation, and shoulder positioning.

Real games need IK solvers that are:

  • Fast — running every frame for potentially dozens of simultaneous limbs
  • Stable — not jittering or flipping between valid solutions
  • Configurable — respecting joint angle limits and preferred resting poses
  • General — working for any chain length in both 2D and 3D

This is why the game industry gravitates toward fast iterative algorithms rather than analytical solutions for chains longer than two segments.

The FABRIK Algorithm

The most popular iterative IK algorithm in real-time applications is FABRIKForward And Backward Reaching Inverse Kinematics, introduced by Andreas Aristidou and Joan Lasenby in 2011. It is both simple to understand and highly effective in practice.

Instead of solving for angles directly, FABRIK works entirely with joint positions. The core idea is two geometric passes per iteration:

The Forward Pass (Tip to Root)

  • Snap the last joint (the end effector) directly to the target position
  • For each joint from the second-to-last backward to the root: pull it toward its child joint, maintaining the original bone length

After this pass, the end effector is exactly at the target — but the root has drifted away from its fixed anchor point.

The Backward Pass (Root to Tip)

  • Snap the root joint back to its original anchored position
  • For each joint from the second onward: push it away from its parent joint, maintaining the original bone length

After this pass, the root is back where it belongs — but the end effector has shifted slightly away from the target again. Repeat both passes until the end effector error $|\vec{p}_{n} - \vec{p}_{target}|$ falls below tolerance $\epsilon$, or until a maximum iteration count is reached. In practice, 5–10 iterations produces stable, convincing results for most chains.

The Math of a Single Pull

Each pull or push operation is geometrically simple. To reposition joint $p_i$ so it lies at distance $l_i$ from joint $p_{i+1}$ (in the forward pass direction):

$$\hat{d} = \frac{p_i - p_{i+1}}{|p_i - p_{i+1}|}$$

$$p_i' = p_{i+1} + l_i \cdot \hat{d}$$

This is equivalent to a linear interpolation, which is how most implementations express it in code:

$$p_i' = \text{lerp}\!\left(p_{i+1},\ p_i,\ \frac{l_i}{|p_i - p_{i+1}|}\right)$$

That is the entire core of the algorithm. No matrix decomposition, no Jacobian pseudoinverse — just repeated vector normalization and scaling, which is why FABRIK runs efficiently even on mobile hardware.

Handling Unreachable Targets

What if the target is farther away than the total chain length $L = \sum_{i} l_i$? Check whether the target is reachable:

$$d = |\vec{p}_{target} - \vec{p}_{root}|$$

If $d > L$, the chain cannot reach the target. Simply align every joint along the direction from root to target — the chain stretches out like a pointing finger.

function fabrik(joints, lengths, target, root, maxIter, tol) {
  var n = joints.length;
  var totalLen = lengths.reduce(function(a, b) { return a + b; }, 0);
  var distToTarget = root.distanceTo(target);

  if (distToTarget > totalLen) {
    // Target unreachable: stretch chain toward it
    for (var i = 0; i < n - 1; i++) {
      var lambda = lengths[i] / joints[i].distanceTo(target);
      joints[i + 1].lerpVectors(joints[i], target, lambda);
    }
    return;
  }

  for (var iter = 0; iter < maxIter; iter++) {
    // Forward pass: pull from tip toward target
    joints[n - 1].copy(target);
    for (var i = n - 2; i >= 0; i--) {
      var d = joints[i + 1].distanceTo(joints[i]);
      joints[i].lerpVectors(joints[i + 1], joints[i], lengths[i] / d);
    }

    // Backward pass: fix the root, push to tip
    joints[0].copy(root);
    for (var i = 0; i < n - 1; i++) {
      var d = joints[i].distanceTo(joints[i + 1]);
      joints[i + 1].lerpVectors(joints[i], joints[i + 1], lengths[i] / d);
    }

    if (joints[n - 1].distanceTo(target) < tol) break;
  }
}

That's the entire solver — roughly 20 lines of readable code that handles any chain length in 2D or 3D space.

Joint Constraints

A naive FABRIK solver can produce anatomically absurd poses — knees bending backward, elbows rotating 270 degrees past their physical limit. Real game implementations add joint constraints to keep poses believable.

Angular Constraints

The most common approach is clamping the angle between consecutive bone directions. After repositioning a joint, measure the angle $\alpha$ between the incoming and outgoing bone vectors:

$$\alpha = \arccos\!\left(\hat{b}_i \cdot \hat{b}_{i+1}\right)$$

If $\alpha$ exceeds the joint's allowed range $[\alpha_{min},\ \alpha_{max}]$, rotate the joint back within bounds. In 2D this is a straightforward angle clamp. In 3D it requires a reference axis to define the constraint plane.

Hinge Constraints

For elbow-like joints that only bend in one axis, constrain movement to a single plane. After each FABRIK step, project the joint back onto the constraint plane:

function applyHingeConstraint(joint, parent, hingeAxis) {
  var dir = joint.clone().sub(parent);
  // Remove component along hinge axis (project onto constraint plane)
  var along = hingeAxis.clone().multiplyScalar(dir.dot(hingeAxis));
  var constrained = dir.clone().sub(along);
  joint.copy(parent).add(constrained.normalize().multiplyScalar(dir.length()));
}

Pole Vectors

In 3D, a chain bent at its midpoint can orient the elbow in infinitely many directions while still reaching the same target. A pole vector resolves this by specifying a point in world space that the elbow should point toward. Unity's Animation Rigging package exposes this as TwoBoneIKConstraint.data.hint, and Unreal Engine's FABRIK node has the same parameter, giving artists control over limb orientation without changing the IK solve.

From 2D to 3D

FABRIK's core algorithm is dimensionally agnostic. The same forward and backward pass logic works in 3D — you substitute 3D vectors for 2D ones. The lerpVectors call doesn't care whether it interpolates in two or three dimensions; the geometry is identical.

A single implementation can handle everything from a flat 2D platformer character's arm to a fully 3D bipedal humanoid skeleton without modification. Dimension-specific code only appears when adding constraints (to define axes and planes) or pole vectors.

Real-World Game Examples

Procedural Foot Placement

In any game with characters traversing uneven terrain — Death Stranding, The Last of Us Part II, Horizon Zero Dawn — the character's feet must conform to the ground surface rather than floating above it or clipping through it. Each leg is an IK chain. Each frame, raycasts below the foot detect the actual terrain height, and an IK target is placed on the surface. The FABRIK solver adjusts the foot and lower leg automatically, creating the weighty, grounded feel that separates polished games from stiff, disconnected animation.

Multi-Legged Creature Animation

Spider-like and insect-like creatures are almost universally animated procedurally with IK. Each leg is an independent IK chain. As the creature body moves, the game places foothold targets around it based on body velocity and available surfaces, and the solver handles how each leg bends to reach those footholds. Subnautica's crabsquids and Satisfactory's spiders use exactly this approach — no hand-keyed animation required.

Weapon and Two-Handed Grips

When a player character holds a rifle, the off-hand must grip the handguard regardless of which animation is playing. The game places an IK target at the handguard's world-space position, runs FABRIK on the off-hand arm chain, and the hand moves to the correct grip, blending with the body's animation. Shooters like Battlefield and RPGs like The Witcher 3 rely heavily on this to make weapon handling feel grounded.

Robotic and Mechanical Characters

Mechanical arms in Horizon Zero Dawn's machines, turrets in Portal, and drone appendages in countless sci-fi games use IK to aim limbs with precision. Because FABRIK runs in $O(n \cdot k)$ time (where $n$ is joint count and $k$ is iterations), dozens of enemies can solve their limb orientations simultaneously with negligible CPU overhead.

Rope, Chain, and Tentacle Simulation

A FABRIK chain with many short segments and one end pinned to a surface produces convincing rope, chain, or tentacle behavior. The algorithm naturally finds a hanging configuration because it minimizes joint displacement while preserving segment lengths. The end can be set to a target (like a hook catching a ledge) while the rest of the chain drapes under its own logic.

IK in Modern Game Engines

Every major engine ships IK tools built on these principles:

  • Unity: The Animator exposes foot and hand IK weights. The Animation Rigging package provides TwoBoneIKConstraint and FABRIKConstraint components with full constraint support.
  • Unreal Engine: The FABRIK AnimGraph node and Two Bone IK node are first-class features used in every major character rig. The IK Retargeting system uses IK to remap animations between skeletons of different proportions without manual re-authoring.
  • Godot: SkeletonIK3D implements FABRIK natively. Godot 4's IK system adds constraint layers and multi-chain support.

Even if you rely on these built-in tools, understanding FABRIK helps you tune iteration counts and tolerances, debug strange poses, and extend the system with custom constraints for non-humanoid creatures.

Performance and Convergence

FABRIK is not guaranteed to converge in the presence of tight angular constraints. With reasonable joint limits and 5–10 iterations, though, real-world performance is excellent:

  • End effector error typically drops below $0.1\%$ of total chain length within 5 iterations
  • Each iteration is $O(n)$ — a 10-joint chain with 10 iterations performs just 200 simple vector operations
  • For very long chains (100+ segments, like ropes), you can limit iterations and accept slight inaccuracy without visible artifacts

For full-body IK where moving the hips affects all four limbs simultaneously, you need multi-root FABRIK, which treats the skeleton as a tree structure. The backward pass visits each branch in sequence using a shared sub-base for joints that connect at a common point (like the pelvis connecting to both legs). Each branch is an independent FABRIK chain, and sub-roots are fixed by their parent branch's result rather than a world anchor.

Conclusion

Once you understand inverse kinematics, you start seeing it everywhere — in the footsteps of AAA characters, the reach of robot arms, the sway of animated tentacles. FABRIK works by turning a nonlinear optimization problem into a geometric one: pull joints toward targets while respecting distances, then pull the root back, and repeat. The math is nothing more than vector normalization and linear interpolation.

The interactive demo at the top of this post lets you explore FABRIK in real time. Move your mouse across it to reposition the target and watch the solver find a natural joint configuration in milliseconds. The chain stretches outward gracefully when the target is out of reach, and converges smoothly as you move the target around. Try implementing your own version with joint angle constraints, and you will have a solid foundation for building everything from procedural spider legs to full-body character IK systems.

Comments

Like this article? Consider supporting us

Your support helps us keep creating free game dev content, tutorials, and tools.

Free

$0 /month

Newsletter and public posts

  • Newsletter access
  • Public posts & updates
  • Community access

Studio Backer

$25 /month

Direct impact on development with your name in the credits

  • Everything in Supporter
  • Your name in game credits
  • Priority feature requests
  • Direct developer access
  • Monthly asset downloads