Article Physics & Mechanics · ≈ ⏱ 11 min read

Constraint satisfaction in physics: the method of Lagrange multipliers

A rope that stays a fixed length, a hinge that only rotates around one axis, a rigid body that never interpenetrates the floor — these are all constraints. Lagrange multipliers give us the exact constraint force that keeps a system on its manifold (the reduced space of positions the constraint allows) without ever simulating the constraint as a stiff spring.

TL;DR: Lagrange multipliers compute the exact force needed to enforce a physical constraint — like a rigid rod or taut rope — without the stiffness problems of spring-based methods. This article covers the constrained equations of motion, the velocity-level constraint form, Baumgarte drift correction, and the sequential impulse solvers used in real-time engines like Box2D and Bullet.

1. Why not just use springs?

Найпростіший спосіб «прив'язати» дві точки — з'єднати їх дуже жорсткою пружиною: F = −k·(|r| − L)·r̂. Проблема в тому, що жорсткість k, потрібна для «нерозтяжної» мотузки, робить систему чисельно жорсткою (stiff) — явний інтегратор вимагає надзвичайно малого dt, інакше симуляція вибухає осциляціями.

Метод множників Лагранжа дозволяє знайти точну силу, яка утримує обмеження — без будь-якої жорсткості чи власної частоти коливань. Це та сама математика, яка лежить в основі узагальненої механіки Лагранжа: мінімізація дії за умови обмежень.

2. Constrained Lagrangian mechanics

Обмеження записують як неявну функцію C(q) = 0, де q — узагальнені координати системи. Наприклад, для жорсткого стрижня довжини L між точками p₁ і p₂:

Distance constraint C(p₁, p₂) = |p₁ − p₂| − L = 0

Рівняння руху з обмеженнями (constrained Euler-Lagrange) додають до звичайних сил доданок λ · ∇C — силу, спрямовану вздовж градієнта обмеження, з невідомим масштабом λ (множник Лагранжа):

Constrained equations of motion M · q̈ = F_ext + Jᵀ · λ
де J = ∂C/∂q — якобіан обмеження (constraint Jacobian)

Множник λ обчислюється так, щоб обмеження точно виконувалось на кожному кроці — не наближено, як з пружиною, а точно (з точністю до похибки чисельного інтегрування).

3. What the multiplier λ actually is

λ — це величина сили обмеження, необхідної, щоб утримати систему на многовиді C(q) = 0. Фізично це натяг мотузки, реакція опори, сила зчеплення в шарнірі. Знак λ несе фізичний зміст: для мотузки λ ≥ 0 (мотузка тягне, але не штовхає) — це однобічне обмеження (unilateral constraint), на відміну від жорсткого стрижня, де λ може бути будь-якого знаку (двобічне, bilateral).

Analogy from optimization

У задачах оптимізації з обмеженнями (Lagrangian duality) λ — це «тіньова ціна» обмеження: наскільки зміниться цільова функція при незначному послабленні обмеження. У фізиці аналог — робота, яку довелось би виконати, щоб трохи розтягнути мотузку.

4. Velocity-level constraint form

У фізичних рушіях реального часу зручніше працювати не з позиційним обмеженням C(q) = 0, а з його похідною за часом — обмеженням на швидкість:

Velocity constraint (differentiate C w.r.t. time) Ċ = J · q̇ = 0

Підставляючи рівняння руху, отримуємо лінійну систему відносно λ:

Solve for λ (single constraint, effective mass) λ = − [J · M⁻¹ · Jᵀ]⁻¹ · J · (M⁻¹ · F_ext + q̇/dt)

Матрицю J · M⁻¹ · Jᵀ називають ефективною масою (effective mass) обмеження — вона показує, наскільки «легко» система реагує на одиничний імпульс уздовж напрямку обмеження.

5. Baumgarte stabilization

Робота лише з Ċ = 0 утримує обмеження на рівні швидкості, але не виправляє накопичену позиційну похибку (drift) через похибки чисельного інтегрування — мотузка поступово «розтягується» на десяті частки відсотка за кроками. Baumgarte-стабілізація додає корекційний доданок, пропорційний позиційній похибці:

Baumgarte-corrected velocity constraint Ċ = J · q̇ = −β/dt · C(q)

Параметр β ∈ [0.1, 0.3] контролює швидкість корекції дрейфу: занадто велике β «висмикує» систему занадто різко (додає штучну енергію), занадто мале — дрейф накопичується видимо. Це компроміс між точністю і стабільністю — типова інженерна проблема числових методів.

Baumgarte is a hack, not physics

Формула Baumgarte не виводиться з механіки — вона є контрольно-інженерним прийомом (PD-контролер на позиційну похибку). Сучасні альтернативи — Position-Based Dynamics (PBD) і XPBD — виправляють похибку геометрично, без введення додаткової «жорсткості».

6. Sequential impulse solvers

Коли обмежень багато (десятки контактів, шарнірів у ragdoll), розв'язання повної системи J·M⁻¹·Jᵀ·λ = b напряму — дорого. Практичні рушії (Box2D, Bullet, PhysX) використовують Sequential Impulse (Projected Gauss-Seidel): розв'язують кожне обмеження окремо, ітеративно, приймаючи інші за фіксовані, поки система не збіжиться.

Sequential impulse — one constraint at a time for iter in 1..N_iterations:
   for each constraint c:
     λ_c ← solve using current velocities
     apply impulse Jᵀ·λ_c immediately

Зазвичай достатньо 4–10 ітерацій для правдоподібної збіжності в реальному часі — точний розв'язок не потрібен, важлива стабільність кадр за кадром.

7. Constraint methods compared

Method Accuracy Cost/step Drift handling Used in
Stiff spring Low Cheap Never satisfied exactly Toy demos
Direct λ solve Exact (per step) O(n³) matrix solve Needs Baumgarte Few-body robotics
Sequential impulse Approximate, iterative O(n · iterations) Warm-starting + Baumgarte Box2D, Bullet, PhysX
PBD / XPBD Geometric, unconditionally stable O(n · iterations) Direct position projection Cloth, this project

8. Псевдокод

Distance constraint with Baumgarte (JS)

// Розв'язати λ для обмеження відстані з Baumgarte-корекцією
function solveDistanceConstraint(a, b, restLength, dt, beta = 0.2) {
  const delta = sub(b.pos, a.pos);
  const dist = length(delta);
  const n = scale(delta, 1 / dist);        // unit direction
  const C = dist − restLength;               // position error

  // Relative velocity along constraint direction
  const relVel = dot(sub(b.vel, a.vel), n);

  // Effective mass along n
  const invMassSum = a.invMass + b.invMass;
  const bias = (beta / dt) * C;             // Baumgarte term

  const lambda = −(relVel + bias) / invMassSum;

  // Apply impulse Jᵀ·λ to both bodies
  a.vel = sub(a.vel, scale(n, lambda * a.invMass));
  b.vel = add(b.vel, scale(n, lambda * b.invMass));
}
▶ Live Demo

See constraints in action

Тканина у цьому проєкті використовує розподілені обмеження відстані для кожного ребра сітки — точно ту математику, що описана вище.

🧣 Cloth Simulation 🌀 Double Pendulum

🔗 Related Simulations

🧵Cloth ⚙️Pendulum 🎱Billiards