Animation
Overview
Animation in computer graphics brings scenes to life by defining how objects, characters, and effects change over time. Techniques range from simple keyframe interpolation to complex physics simulations, each suited to different levels of realism and control.
Keyframe Animation
Principle
Define poses (key values) at specific times. The system interpolates between them to produce smooth motion.
Time: 0.0 0.5 1.0 1.5 2.0
Value: 0 30 60 45 0 (e.g., rotation in degrees)
Linear Interpolation (Lerp)
v(t) = (1 - alpha) * v0 + alpha * v1, alpha = (t - t0) / (t1 - t0)
Simple but produces abrupt changes at keyframes (C0 continuity only).
Interpolation Curves
Bezier Curves
Defined by control points. A cubic Bezier uses 4 points (P0, P1, P2, P3):
B(t) = (1-t)^3 * P0 + 3(1-t)^2 * t * P1 + 3(1-t) * t^2 * P2 + t^3 * P3
Properties:
- Passes through P0 and P3 (endpoints)
- Tangent at P0 is toward P1; tangent at P3 is from P2
- Lies within the convex hull of control points
- Affine invariant
Animators control easing by adjusting the interior control points (ease-in, ease-out, overshoot).
Catmull-Rom Splines
Interpolating spline that passes through all control points. Given points P_{i-1}, P_i, P_{i+1}, P_{i+2}:
q(t) = 0.5 * [(2*P_i) +
(-P_{i-1} + P_{i+1}) * t +
(2*P_{i-1} - 5*P_i + 4*P_{i+1} - P_{i+2}) * t^2 +
(-P_{i-1} + 3*P_i - 3*P_{i+1} + P_{i+2}) * t^3]
C1 continuous. Tangent at each point is derived from neighbors: T_i = 0.5 * (P_{i+1} - P_{i-1}).
Widely used for camera paths and animation curves due to intuitive control (points lie on the curve).
Hermite Splines
Defined by positions and tangents at each endpoint. Cubic Hermite basis:
h(t) = h00*p0 + h10*m0 + h01*p1 + h11*m1
h00 = 2t^3 - 3t^2 + 1
h10 = t^3 - 2t^2 + t
h01 = -2t^3 + 3t^2
h11 = t^3 - t^2
Catmull-Rom is a special case of Hermite interpolation with specific tangent computation.
Rotation Interpolation
Euler Angles
Represent rotation as three angles (roll, pitch, yaw). Simple but suffers from:
- Gimbal lock: Loss of one degree of freedom when two axes align
- Interpolation artifacts: Lerping Euler angles produces unexpected paths
Quaternions
Rotation represented as q = (w, x, y, z) = w + xi + yj + zk, where |q| = 1.
A rotation of angle theta about unit axis a:
q = (cos(theta/2), sin(theta/2) * a)
Rotating a point p: p' = q * p * q^(-1) (where p is embedded as a pure quaternion).
Advantages: compact (4 floats), no gimbal lock, smooth interpolation, easy composition (multiplication).
SLERP (Spherical Linear Interpolation)
Interpolates along the shortest arc on the unit quaternion sphere:
slerp(q0, q1, t) = q0 * sin((1-t)*theta) / sin(theta) + q1 * sin(t*theta) / sin(theta)
Where theta = acos(q0 . q1). If q0 . q1 < 0, negate one quaternion to take the short path.
Constant angular velocity (unlike lerp followed by normalization, which varies speed).
SQUAD (Spherical Cubic Interpolation)
For smooth interpolation through multiple rotations (analogous to cubic splines):
squad(q_i, q_{i+1}, s_i, s_{i+1}, t) = slerp(slerp(q_i, q_{i+1}, t), slerp(s_i, s_{i+1}, t), 2t(1-t))
Where s_i are intermediate control quaternions computed from neighboring keyframes.
Skeletal Animation
Skeleton Hierarchy
A skeleton is a tree of joints (bones). Each joint stores a local transform relative to its parent:
Joint 0 (root): T_local_0
Joint 1 (spine): T_local_1
Joint 2 (shoulder): T_local_2
Joint 3 (elbow): T_local_3
World transform of joint j: T_world_j = T_world_parent * T_local_j (recursive chain).
Skinning
Each vertex is associated with one or more joints via weights. The vertex position is computed from the joint transforms.
Bind pose matrix B_j: The world transform of joint j in the rest pose. Inverse bind matrix: B_j^(-1) transforms a vertex from model space to joint-local space.
Linear Blend Skinning (LBS)
The most common skinning method:
v' = sum_{j} w_j * (T_world_j * B_j^(-1)) * v
Where w_j are the blend weights (sum to 1, typically 4 per vertex max).
Artifacts: Produces the "candy wrapper" effect at twisted joints and volume loss at bent joints (elbows, shoulders). This is because linearly blending matrices does not preserve rigidity.
Dual Quaternion Skinning (DQS)
Represents joint transforms as dual quaternions and blends them:
dq = sum_{j} w_j * dq_j // weighted sum of dual quaternions
dq = dq / |dq| // normalize
v' = transform(dq, v)
A dual quaternion encodes both rotation (quaternion) and translation:
dq = q_real + epsilon * q_dual
q_real = rotation quaternion
q_dual = 0.5 * t * q_real (where t is the translation quaternion)
Advantages over LBS: preserves volume, eliminates candy-wrapper artifacts. Slightly more expensive but widely adopted in games.
Animation Blending
Combine multiple animations (e.g., walk + wave):
- Lerp blending: Interpolate bone transforms between two animations
- Additive blending: Add a delta animation on top of a base pose
- Blend trees: Parameterized blending (e.g., walk speed controls blend between walk/run)
- Animation state machines: Transitions between states with crossfade durations
Inverse Kinematics (IK)
Given a target position for an end-effector (e.g., hand, foot), compute the joint angles that achieve it. The inverse of forward kinematics.
Cyclic Coordinate Descent (CCD)
Iterative method that adjusts one joint at a time, from the end-effector toward the root:
for each iteration:
for j = end_effector_parent down to root:
v_to_end = end_effector_pos - joint[j].pos
v_to_target = target_pos - joint[j].pos
rotation = rotation_from_to(v_to_end, v_to_target)
joint[j].rotation *= rotation
apply constraints (angle limits)
Converges quickly but can produce unnatural poses. Joint angle constraints help.
FABRIK (Forward And Backward Reaching IK)
Operates on joint positions rather than angles. Two passes per iteration:
Forward pass (end-effector to root):
- Move end-effector to target
- For each joint from end toward root: place it at distance d (bone length) from the next joint toward the target chain
Backward pass (root to end-effector):
- Move root back to its fixed position
- For each joint from root toward end: place it at distance d from the previous joint
Converges in very few iterations. Natural-looking results.
Easily handles multiple end-effectors and constraints.
Physics-Based Animation
Rigid Body Dynamics
Objects with mass but no deformation. State: position, orientation, linear velocity, angular velocity.
F = m * a // Newton's second law
tau = I * alpha // Torque and angular acceleration
I = R * I_body * R^T // World-space inertia tensor
Integration (semi-implicit Euler):
v(t+dt) = v(t) + (F/m) * dt
x(t+dt) = x(t) + v(t+dt) * dt
Collision detection: broad phase (spatial hashing, BVH) then narrow phase (GJK, SAT). Contact resolution via impulse-based or constraint-based solvers.
Soft Body / Deformable Bodies
- Mass-spring systems: Particles connected by springs (Hooke's law). Simple but hard to tune and not volume-preserving.
- Finite Element Method (FEM): Discretize continuum mechanics equations on a tetrahedral mesh. Physically accurate but expensive.
- Position-Based Dynamics (PBD): Directly manipulate positions to satisfy constraints. Stable, fast, controllable. Used in many game engines.
Cloth Simulation
Modeled as a mesh of particles with structural, shear, and bending springs (or PBD constraints).
Key forces: gravity, wind, spring/constraint forces, collision response.
For each timestep:
Apply external forces (gravity, wind)
Integrate velocities and positions
Solve constraints (distance, bending, collision) iteratively
Update velocities from position changes
Self-collision detection is expensive; spatial hashing or BVH on cloth triangles.
Fluid Simulation
- Eulerian (grid-based): Solve Navier-Stokes on a fixed grid. Steps: advection, diffusion, pressure solve (Poisson equation), projection.
- Lagrangian (particle-based): SPH (Smoothed Particle Hydrodynamics) or FLIP/PIC. Particles carry fluid properties, kernel-weighted interactions.
- Hybrid: FLIP/APIC combine particles (advection) with a grid (pressure solve). State of the art for liquid simulation.
Surface extraction: marching cubes on a level set or particle-based surface reconstruction.
Particle Systems
Emit, simulate, and render large numbers of small elements (sparks, smoke, rain, fire).
Lifecycle
for each frame:
Emit new particles (position, velocity, lifetime, color, size)
Update existing particles:
apply forces (gravity, wind, turbulence)
integrate position
age += dt
if age > lifetime: remove
Sort (for transparency) and render (billboards, trails, meshes)
GPU Particle Systems
- Store particles in GPU buffers
- Compute shader updates positions and emits/kills particles
- Indirect draw for variable particle count
- Millions of particles at interactive rates
Rendering Techniques
- Billboards: Camera-facing quads with a sprite texture
- Ribbon/trail: Connect sequential positions into a strip
- Mesh particles: Instance a mesh per particle
- Volumetric: Splat particles into a 3D texture, ray-march for smoke/fog