Verlet Integration Under the Hood: A Step-by-Step Walkthrough

Verlet Integration Under the Hood: A Step-by-Step Walkthrough

A game physics engine developer's guide to numerical integration — covering Euler instability, Verlet math, distance constraints relaxation, and cloth simulators.

Simulating the physical world in code is one of the most exciting aspects of game development. When we model bouncing balls, swinging pendulums, dangling ropes, or tearing cloth, we must compute their positions and velocities continuously over time.

Because computers operate in discrete steps (frames) rather than continuous time, we cannot solve equations of motion using smooth calculus. Instead, we use **Numerical Integration**. While most beginners start with simple Euler integration, they quickly discover its limitations: objects gain infinite energy, orbits spiral out of control, and constraints collapse. To build stable physics engines, developers turn to **Verlet Integration**. This guide traces the mathematics of Verlet integration, explains constraint relaxation loops, outlines cloth modeling, and simulates particle constraints in our interactive physics sandbox.


1. The Numerical Integration Challenge: Simulating Motion

1.1 Continuous Calculus vs Discrete Frames

Newton's second law of motion states that force equals mass times acceleration ($F = ma$). In physics simulations, we know the forces acting on a particle (like gravity or wind), allowing us to calculate its acceleration $a = F/m$. To find the particle's velocity and position, we must integrate acceleration over time. In continuous mathematics, velocity is the integral of acceleration, and position is the integral of velocity.

In a game engine, time advances in small discrete steps $\Delta t$ (e.g. $\Delta t \approx 16.67$ milliseconds for a 60 FPS target). We must use numerical approximations to update position and velocity values step-by-step. The choice of the integration algorithm determines the stability, accuracy, and performance of our physics engine.

1.2 Physical State Vectors vs Discrete Ticks

Continuous integration tracks infinite coordinates. Discrete ticks calculate positions using state vectors updated at interval boundaries.

Common Misconception — High frame rates guarantee physics engine stability: A common developer misconception is that a high frame rate alone guarantees physics stability. In reality, if your integration algorithm accumulates energy (like Explicit Euler), running at higher frame rates only delays the inevitable explosion. If the time-step $\Delta t$ increases temporarily during a lag spike, the error accumulates exponentially, causing objects to blast off out of the game world.


2. Euler Integration: The Traditional Approach

2.1 Explicit Euler Instability

The simplest integration method is **Explicit Euler**. At each step, we update position using the current velocity, and update velocity using the current acceleration:

$$ \begin{aligned} x_{t+\Delta t} &= x_t + v_t \Delta t \\ v_{t+\Delta t} &= v_t + a_t \Delta t \end{aligned} $$

Explicit Euler is popular because it requires only two lines of code. However, it is mathematically unstable (an first-order method). It assumes that velocity remains constant over the entire step $\Delta t$, which is false. In orbit simulations, Explicit Euler constantly overestimates position, adding kinetic energy to the system. Over time, a orbiting planet will spiral away from its sun, violating the conservation of energy.

graph TD A["Calculate Forces"] E["Explicit Euler: x = x + v*dt"] V["Velocity Update: v = v + a*dt"] A --> E E --> V

Mermaid Diagram: The logical update sequence of the Explicit Euler integration model.


3. Verlet Integration: Velocity-Free Physics

3.1 Position-Based Physics

To resolve the instability of Euler, Loup Verlet developed **Verlet Integration** for molecular dynamics. Crucially, Verlet integration does not store velocity variables. Instead, it tracks the particle's **Current Position ($x_t$)** and **Previous Position ($x_{t-\Delta t}$)**.

The velocity is calculated implicitly by subtracting the previous position from the current position. Because velocity is derived directly from actual displacement, the system is self-correcting: it is physically impossible for the velocity to drift away from the coordinates, ensuring excellent energy conservation.


4. The Mathematical Derivation of Verlet Integration

4.1 Taylor Series Expansion

To understand why Verlet is stable, we derive it using Taylor series expansions for the position function $x(t)$ in both the forward and backward directions:

$$ \begin{aligned} x(t+\Delta t) &= x(t) + x'(t)\Delta t + \frac{1}{2}x''(t)\Delta t^2 + \frac{1}{6}x'''(t)\Delta t^3 + O(\Delta t^4) \\ x(t-\Delta t) &= x(t) - x'(t)\Delta t + \frac{1}{2}x''(t)\Delta t^2 - \frac{1}{6}x'''(t)\Delta t^3 + O(\Delta t^4) \end{aligned} $$

Where $x'(t)$ is velocity $v(t)$, and $x''(t)$ is acceleration $a(t)$. Adding these two equations cancels out the odd-order derivative terms (such as velocity and jerk):

$$ x(t+\Delta t) + x(t-\Delta t) = 2x(t) + a(t)\Delta t^2 + O(\Delta t^4) $$

Rearranging the terms to solve for the next position $x(t+\Delta t)$ yields the standard Verlet update equation:

$$ x_{t+\Delta t} = 2x_t - x_{t-\Delta t} + a_t \Delta t^2 $$

Because the third-order derivative terms cancel out, Verlet integration is a second-order accurate method. The local truncation error is $O(\Delta t^4)$, making it far more accurate than Euler integration with zero additional computational cost.


5. Constraint Solving in Verlet Systems

5.1 Distance Constraint Relaxation

In physics engines, constraint solving coordinates relationships between particles (e.g. keeping two rope segments linked by a fixed distance $L$). In Euler systems, resolving constraints requires calculating complex impulse forces, which often leads to solver failures.

In Verlet systems, we use **Distance Constraint Relaxation** (or Jakobsen's method). Instead of computing forces, we look at the actual distance $D$ between two particles. If $D \neq L$, we calculate the displacement error and shift the particle coordinates directly to restore the target distance $L$. Because velocity is derived from position shifts, this coordinate change automatically adjusts the implicit velocities, resolving constraints stably.


6. Managing Time-Steps: The Dangers of Variable delta t

6.1 Time-Step Glitch Explosions

The standard Verlet update equation assumes that the time-step $\Delta t$ is constant. If $\Delta t$ changes dynamically between frames (due to garbage collection spikes or render lags), the implicit velocity calculation breaks down, causing objects to accelerate or decelerate incorrectly.

To prevent this, physics engines use **Time-Step Correction**. We multiply the displacement term by the ratio of the current time-step to the previous time-step, or use a fixed physics accumulator (such as `FixedUpdate` in Unity) to execute physics updates in uniform ticks.

6.2 Time-Step Correction Formulas and fixed Accumulator Loops

Let $\Delta t$ be the current frame time-step, and let $\Delta t_{\text{prev}}$ be the time-step of the previous frame. If they are unequal, the standard Verlet position update will multiply the previous velocity term incorrectly. The **Time-Step Corrected Verlet** update adjusts the displacement factor by their ratio:

$$ x_{t+\Delta t} = x_t + (x_t - x_{t-\Delta t_{\text{prev}}}) \left(\frac{\Delta t}{\Delta t_{\text{prev}}}\right) + a_t \Delta t^2 $$

While this correction scale factor reduces glitches, high ratios (e.g. during a major lag spike where $\Delta t / \Delta t_{\text{prev}} > 5$) will still cause numerical integration errors. The industry standard solution is to decouple the rendering frame rate from the physics engine update rate using a **Fixed Time-Step Accumulator**.

Instead of integrating with variable frame times, the engine queues elapsed time into an accumulator buffer. The physics solver then runs updates using a fixed time-step $\Delta t_{\text{physics}}$ (typically 10ms or 16.6ms) as long as the accumulator contains enough time credit:

double accumulator = 0.0;
double dt_physics = 0.01666; // Fixed 60Hz tick
 
void updateGameLoop(double frameTime) {
    accumulator += frameTime;
    
    -- Consume time credit in fixed ticks
    while (accumulator >= dt_physics) {
        integratePhysicsState(dt_physics);
        resolveConstraints();
        accumulator -= dt_physics;
    }
    
    -- Interpolate remaining remainder for rendering
    double alpha = accumulator / dt_physics;
    interpolateRenderState(alpha);
}

This fixed accumulator loop guarantees that the physics engine executes identical numerical updates on all machines, regardless of frame rate fluctuations. Below is a comparison table of time integration parameters:

Timing Strategy Time-Step ($\Delta t$) Values Numerical Consistency Physics Simulation Cost
Variable Frame Tick Variable (equal to frame render time) Poor (susceptible to clipping and jitter) Low (exactly 1 update per frame)
Corrected Verlet Variable (ratio-adjusted displacement) Medium (reduces spikes but remains variable) Low
Fixed Accumulator Fixed constant ($\Delta t_{\text{physics}}$) Perfect (100% deterministic runs) Variable (runs multiple times if frame lags)

Pitfall — The Spiral of Death: If the physics integration phase takes longer to compute than $\Delta t_{\text{physics}}$, the accumulator queue will grow on every frame. This forces the while loop to run more times in the next frame, further increasing render latency, locking the game. Prevent this by clamping the maximum accumulated time to a safety limit (e.g. 100ms).


7. Advanced: Verlet integration with angular forces and rigid bodies

7.1 Rigid Body Constraints

While Verlet is inherently particle-based, we can model rigid bodies by grouping particles and linking them with rigid distance constraints (sticks). For example, a rigid square can be modeled using 4 particles at the corners and 6 sticks (including diagonals) to prevent shearing.

This eliminates the need for expensive angular velocity vectors and rotation matrices, making Verlet engines ideal for ragdoll systems and destructible structures.

7.2 Distance Constraint Relaxation Vector Mathematics

To solve a distance constraint between two particles at positions $\vec{p}_1 = (x_1, y_1)$ and $\vec{p}_2 = (x_2, y_2)$ linked by a target rest length $L$, we first calculate the difference vector $\vec{\Delta}$ and its Euclidean length $D$:

$$ \begin{aligned} \vec{\Delta} &= \vec{p}_2 - \vec{p}_1 \\ D &= \|\vec{\Delta}\| = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2} \end{aligned} $$

If $D \neq L$, the constraint is violated. The scalar error difference is $\text{diff} = D - L$. To resolve this error, we shift both particles along the line of action $\vec{\Delta} / D$. If both particles have equal mass, we shift each by half the error:

$$ \vec{\delta} = \frac{1}{2} (D - L) \frac{\vec{\Delta}}{D} $$

The updated coordinates are obtained by shifting particle 1 forward and particle 2 backward:

$$ \begin{aligned} \vec{p}_1^{\text{new}} &= \vec{p}_1 + \vec{\delta} \\ \vec{p}_2^{\text{new}} &= \vec{p}_2 - \vec{\delta} \end{aligned} $$

If the particles have different masses $m_1$ and $m_2$, we distribute the displacement shifts inversely proportional to their masses. Let $w_1 = 1/m_1$ and $w_2 = 1/m_2$ be the inverse masses. The displacement scale is normalized by the total inverse mass $w_{\text{total}} = w_1 + w_2$:

$$ \begin{aligned} \vec{p}_1^{\text{new}} &= \vec{p}_1 + \frac{w_1}{w_{\text{total}}} (D - L) \frac{\vec{\Delta}}{D} \\ \vec{p}_2^{\text{new}} &= \vec{p}_2 - \frac{w_2}{w_{\text{total}}} (D - L) \frac{\vec{\Delta}}{D} \end{aligned} $$

In a complex network of constraints (like a cloth grid or a ragdoll skeleton), resolving one constraint will pull other particles, violating neighboring sticks. We solve this by running multiple relaxation sweeps (iterations) per frame. Below is a comparison table of Verlet structural components:

Constraint Type Mathematical Evaluation Equation Physical Behavior Typical Usage in Engines
Distance Stick $\|\vec{p}_2 - \vec{p}_1\| - L = 0$ Maintains rigid distance between endpoints Rope links, bridge trusses, structural skeletons
Pin Anchor $\vec{p}_i - \vec{p}_{\text{fixed}} = 0$ Locks a particle to a static coordinate Rope hanger supports, hinges, swinging pendulums
Angular Clamp $\cos\theta - \cos\theta_{\text{target}} = 0$ Restricts rotational angle range between three nodes Ragdoll elbow and knee bending limits

Pitfall — Solver locking via circular constraints: If a loop of rigid distance sticks is over-constrained (e.g. attempting to force diagonals of a triangle to be longer than the sum of sides), the relaxation loop will oscillate infinitely, causing the structure to jitter or explode. Always ensure constraints are physically possible before execution.


8. Advanced: Comparison of Numerical Integration Methods

8.1 Integration Strategy Matrix

The table below compares the mathematical accuracy, stability, and applications of different integration algorithms:

8.2 Symplectic Geometry and Solver Trade-offs

In physics engine design, choosing an integration algorithm requires balancing accuracy, stability, and execution speed. Let $N$ be the number of particles in the simulation. The computational overhead and performance characteristics differ significantly:

  • **Explicit Euler**: Requires 1 force evaluation per step, but drifts rapidly, requiring very small $\Delta t$ to avoid explosions.
  • **Semi-Implicit Euler**: Symplectic integrator of 1st order. Requires 1 force evaluation. It is highly stable for rigid bodies and character controllers, and is the default choice for general 2D/3D physics engines (like Box2D or PhysX).
  • **Verlet Integration**: Symplectic integrator of 2nd order. Requires 1 force evaluation. Position-based shifts make constraint solving extremely stable, making it the standard choice for cloth and soft body dynamics.
  • **Runge-Kutta 4 (RK4)**: 4th-order accurate, but requires 4 force evaluations per step. It is computationally expensive, making it unsuitable for hundreds of particles in real-time games, but ideal for high-precision orbit trajectory tracking.
Integration Method Truncation Error Order Energy Conservation Ideal Use Case
Explicit Euler $O(\Delta t)$ (1st order) Poor (accumulates energy) None (avoid for physical simulations)
Semi-Implicit Euler $O(\Delta t)$ (1st order) Good (symplectic integrator) Standard 3D character controllers and rigid body dynamics
Verlet Integration $O(\Delta t^2)$ (2nd order) Excellent (conserves phase space) Ropes, ragdolls, cloth simulation, soft bodies
Runge-Kutta 4 (RK4) $O(\Delta t^4)$ (4th order) Excellent High-precision space flight and aerospace simulators

Pitfall — Ignoring collision boundaries during relaxation: When resolving constraint overlaps, shifting a particle's coordinates directly might push it through a thin static collision boundary (like a wall). Always verify boundaries *after* resolving internal constraints, clamping coordinates to valid spaces to prevent clipping glitches.


9. Complete Verlet Physics Engine in JavaScript

9.1 The Class Code

The following JavaScript code implements a basic Verlet particle and distance stick solver, executing coordinate relaxation sweeps:

class VerletParticle {
    constructor(x, y) {
        this.x = x; this.y = y;
        this.oldX = x; this.oldY = y;
    }
 
    update(dt, gravity) {
        const tempX = this.x;
        const tempY = this.y;
        
        // Verlet update: x_new = 2x - x_old + a * dt^2
        this.x = 2 * this.x - this.oldX;
        this.y = 2 * this.y - this.oldY + gravity * dt * dt;
        
        this.oldX = tempX;
        this.oldY = tempY;
    }
}

10. Interactive: Verlet Rope and Particle Simulator

Click "Apply Wind Force" to push the rope particles. Click "Resolve Constraints" to relax the distance offsets back to their target length:

Status: Ready
Rope Length: 3 segments, 50px each.
Log output displays here...

Energy Drift Comparison: Explicit Euler vs Verlet

The chart below compares the total physical energy of a simple pendulum over time using Explicit Euler vs Verlet integration, illustrating how Euler gains energy and explodes:


12. Frequently Asked Questions

Q1: Why does Verlet integration not store velocity?

Because velocity can be derived implicitly by subtracting the previous position from the current position. This ensures velocity matches actual coordinates, preventing energy drift.

Q2: How does Verlet handle friction or air resistance?

Friction is modeled by scaling the displacement term slightly. For example, replacing $2x_t - x_{t-dt}$ with $x_t + 0.99(x_t - x_{t-dt})$ reduces velocity by 1% per frame, simulating drag.

Q3: What is constraint relaxation?

Constraint relaxation is an iterative method where the solver evaluates each constraint sequentially and shifts coordinates directly to resolve discrepancies, repeating the loop to converge on a global solution.

Q4: Why does Explicit Euler explode in orbital simulations?

Because it calculates position updates using the velocity from the *beginning* of the time-step. When orbiting, the velocity points tangentially, meaning the particle constantly overshoots its circular path, gaining energy.

Q5: What is a symplectic integrator?

A symplectic integrator is a numerical method designed to conserve phase space volume (representing physical energy). Semi-Implicit Euler and Verlet are symplectic, preserving long-term stability.

Q6: How do we model a tearing cloth using Verlet?

We represent the cloth as a 2D grid of particles linked by distance sticks. If the distance between two particles exceeds a breaking threshold (e.g. 1.5 times the rest length), we delete that stick constraint from the solver.

Q7: Can Verlet be used for high-precision celestial mechanics?

While stable, Verlet is only second-order accurate. For high-precision scientific spaceflight trajectories, astronomers prefer 4th-order Runge-Kutta (RK4) or symplectic integrators of higher orders.

Q8: How do I debug constraint solver instability in my physics engine?

Verify: (1) check that time-steps are clamped or fixed, (2) increase the number of relaxation iterations per frame, (3) verify that constraints are not conflicting (e.g., sticking a particle to two locations simultaneously), and (4) verify that collision response shifts do not generate infinite forces.

Post a Comment

Previous Post Next Post