Формули ігрової фізики — шпаргалка
Усі ключові рівняння для побудови фізичних рушіїв реального часу: імпульс-імпульс тіла, обробка зіткнень із тертям, системи пружина-демпфер, динаміка твердих тіл, тензори інерції для поширених форм та порівняння методів числового інтегрування.
1. Кінематика та закони Ньютона
F = m·a a = F/m
Другий закон Ньютона (обертальний):
τ = I·α α = I⁻¹·τ
Кінематичне інтегрування (на крок часу dt):
v += a·dt
x += v·dt
Кінетична енергія:
KE_trans = ½·m·v²
KE_rot = ½·ω·I·ω
Імпульс:
p = m·v (лінійний)
L = I·ω (момент імпульсу)
| Символ | Значення | Одиниця SI |
|---|---|---|
m |
маса | кг |
F |
сила | Н = кг·м/с² |
a |
прискорення | м/с² |
v |
швидкість | м/с |
x |
позиція | м |
τ |
момент сили | Н·м |
I |
тензор моменту інерції | кг·м² |
α |
кутове прискорення | рад/с² |
ω |
кутова швидкість | рад/с |
2. Імпульс та обробка зіткнень
Коли два тверді тіла стикаються в точці контакту P, ми прикладаємо імпульс J уздовж нормалі контакту n̂.
v_rel = (v_A + ω_A × r_A) − (v_B + ω_B × r_B)
v_n = dot(v_rel, n̂) (нормальна складова, від'ємна = зближення)
Величина імпульсу (без тертя):
j = −(1 + e) · v_n / K
Ефективна маса K:
K = 1/m_A + 1/m_B
+ dot((I_A⁻¹·(r_A × n̂)) × r_A, n̂)
+ dot((I_B⁻¹·(r_B × n̂)) × r_B, n̂)
Оновлення швидкості:
v_A' = v_A + (j/m_A)·n̂
ω_A' = ω_A + I_A⁻¹·(r_A × j·n̂)
v_B' = v_B − (j/m_B)·n̂
ω_B' = ω_B − I_B⁻¹·(r_B × j·n̂)
e = коефіцієнт відновлення (0 = абсолютно непружне, 1 = пружне)
| Пара матеріалів | e (приблизно) |
|---|---|
| Сталь по сталі | 0.55–0.75 |
| Гумовий м'яч об підлогу | 0.75–0.85 |
| Супер-м'яч | 0.90–0.95 |
| Глина по глині | 0 (пластичний удар) |
| Скло по склу | 0.95 |
| М'яч для гольфу | 0.68 |
| Баскетбольний м'яч | 0.70–0.75 |
function resolveCollision(bodyA, bodyB, contact) {
const n = contact.normal; // одинична нормаль A→B
const rA = contact.point.sub(bodyA.pos);
const rB = contact.point.sub(bodyB.pos);
const vRel = bodyA.vel.add(rA.cross(bodyA.angVel))
.sub(bodyB.vel).sub(rB.cross(bodyB.angVel));
const vn = vRel.dot(n);
if (vn >= 0) return; // розходяться — пропустити
const e = 0.7;
const rAxN = rA.cross(n), rBxN = rB.cross(n);
const K = bodyA.invMass + bodyB.invMass
+ rAxN.dot(bodyA.invInertia.mulVec(rAxN))
+ rBxN.dot(bodyB.invInertia.mulVec(rBxN));
const j = -(1 + e) * vn / K;
bodyA.vel = bodyA.vel.add(n.scale(j * bodyA.invMass));
bodyB.vel = bodyB.vel.sub(n.scale(j * bodyB.invMass));
bodyA.angVel = bodyA.angVel.add(bodyA.invInertia.mulVec(rAxN).scale(j));
bodyB.angVel = bodyB.angVel.sub(bodyB.invInertia.mulVec(rBxN).scale(j));
}
3. Тертя та контактні сили
|f_t| ≤ μ · |f_n|
Якщо ковзає: f_t = −μ_k · |f_n| · t̂ (кінетичне тертя)
Якщо не ковзає: |f_t| ≤ μ_s · |f_n| (конус статичного тертя)
μ_s ≈ 1.2–1.4 × μ_k (статичне завжди трохи більше)
Тертя на основі імпульсу (дотичний імпульс):
v_t = v_rel − dot(v_rel, n̂)·n̂ (дотична відносна швидкість)
j_t = −dot(v_t, t̂) / K_t (дотичний імпульс)
Обмеження: |j_t| ≤ μ·|j_n| (конус тертя)
| Пара матеріалів | μ_s (статичне) | μ_k (кінетичне) |
|---|---|---|
| Сталь по сталі (суха) | 0.74 | 0.57 |
| Сталь по сталі (змащена) | 0.15 | 0.09 |
| Гума по бетону (суха) | 0.8 | 0.75 |
| Дерево по дереву | 0.4 | 0.2 |
| Лід по льоду | 0.03 | 0.02 |
| Тефлон по тефлону | 0.04 | 0.04 |
friction_impulse = clamp(j_t, -μ·j_n, +μ·j_n). Щоб
розрізнити статичне/кінетичне, перевірте, чи перевищує швидкість
дотичного ковзання малий поріг (наприклад, 0.01 м/с).
4. Системи пружина-демпфер
F_spring = −k · (x − x_rest)
Демпфер (в'язкий):
F_damper = −c · v
Пружина-демпфер разом:
F = −k·Δx − c·v
Критичне демпфування:
c_critical = 2·√(k·m)
Коефіцієнт демпфування:
ζ = c / (2·√(k·m))
ζ < 1: недодемпфоване (коливається)
ζ = 1: критично демпфоване (найшвидше повернення, без коливань)
ζ > 1: передемпфоване (повільне повернення)
Власна частота:
ω_n = √(k/m) [рад/с]
f_n = ω_n / (2π) [Гц]
Обертальна пружина (крутильна)
Та сама формула коефіцієнта демпфування: ζ = c_r / (2·√(k_r · I))
// Сила пружини-демпфера між двома з'єднаними тілами
function springDamper(posA, posB, velA, velB, restLength, k, c) {
const delta = posB.sub(posA);
const dist = delta.length();
if (dist < 1e-8) return Vec3.zero;
const dir = delta.scale(1/dist);
const stretch = dist - restLength;
const relVel = velB.sub(velA).dot(dir); // знакова швидкість уздовж пружини
const force = k * stretch + c * relVel;
return dir.scale(force); // застосувати до A; для B змінити знак
}
5. Динаміка твердих тіл
Позиція: x ∈ ℝ³
Орієнтація: q ∈ SO(3) (бажано кватерніон)
Лінійний імпульс: p = m·v
Момент імпульсу: L = I_world · ω
Тензор інерції у світовому просторі:
I_world = R · I_body · R^T
(R = матриця обертання з кватерніона)
Рівняння руху:
dx/dt = v = p/m
dp/dt = F_ext
dq/dt = ½ · Q(ω) · q (похідна кватерніона)
dL/dt = τ_ext
ω = I_world⁻¹ · L
Сила від коріолісового члена кутової швидкості (обертова система):
Зауваження: ω × (ω × r) — доцентрова, ω × v — коріолісова — потрібні лише в обертових системах відліку.
Інтегрування кватерніонів
dq/dt = ½ · [0, ω] ⊗ q
Інтегрування (явний Ейлер, мале dt):
q += ½ · [0, ω] ⊗ q · dt
q = normalize(q) <-- ВАЖЛИВО: перенормовуйте на кожному кроці
function integrateRigidBody(body, dt) {
// Оновити лінійний стан
body.vel.addScaledVector(body.force, body.invMass * dt);
body.pos.addScaledVector(body.vel, dt);
// Оновити кутовий стан
body.angVel.addScaledVector(body.torque, body.invInertiaWorld * dt); // спрощений скаляр
// Інтегрувати кватерніон
const dq = new Quaternion(0, body.angVel.x, body.angVel.y, body.angVel.z)
.multiply(body.orient).scale(0.5 * dt);
body.orient.add(dq).normalize();
// Скинути сили
body.force.set(0,0,0);
body.torque.set(0,0,0);
}
6. Довідник тензорів інерції
Усі тензори діагональні у власному просторі тіла (вирівняні з осями симетрії). R = радіус, L = довжина, a/b/c = піврозміри.
Суцільна куля (маса m, радіус R)
Порожниста сфера (тонка оболонка)
Суцільний циліндр (вісь уздовж z, радіус R, висота H)
I_zz = mR²/2
Суцільний паралелепіпед (піврозміри a, b, c уздовж x, y, z)
I_yy = m(a² + c²)/3
I_zz = m(a² + b²)/3
Суцільний конус (радіус R, висота H, вершина вгорі, основа центрована)
I_zz = 3mR²/10
Тонкий стрижень (довжина L, вісь уздовж z)
I_zz ≈ 0
I'_xx = I_xx + m·(dy² + dz²)
I'_yy = I_yy + m·(dx² + dz²)
I'_zz = I_zz + m·(dx² + dy²)
7. Числове інтегрування
| Метод | Порядок | Енергія | Випадок застосування |
|---|---|---|---|
| Явний Ейлер | 1-й | Набирає енергію | Прості демо, нестабільний для жорстких пружин |
| Напівнеявний Ейлер | 1-й (симплектичний) | Зберігає (майже) | Тверді тіла, типовий для фізичних рушіїв |
| Верле | 2-й | Добре зберігає | Системи частинок, тканина, молекулярна динаміка |
| Velocity Verlet | 2-й | Добре зберігає | Стандарт для MD і фізичних рушіїв |
| «Чехарда» (Leapfrog) | 2-й | Симплектичний | Гравітація N тіл, орбітальна механіка |
| RK4 | 4-й | Трохи дисипативний | Точні траєкторії, мале dt |
v(t+dt) = v(t) + a(t)·dt
x(t+dt) = x(t) + v(t+dt)·dt <-- використовує нову швидкість
Velocity Verlet:
x(t+dt) = x(t) + v(t)·dt + ½·a(t)·dt²
a(t+dt) = F(x(t+dt))/m
v(t+dt) = v(t) + ½·(a(t) + a(t+dt))·dt
«Чехарда»:
v(t+½dt) = v(t−½dt) + a(t)·dt
x(t+dt) = x(t) + v(t+½dt)·dt
8. Сили обмежень та з'єднання
Обмеження зменшують ступені свободи, прикладаючи коригувальні імпульси на кожному кроці часу. Якобіан обмеження J відображає похибку обмеження на узагальнені сили.
C = |x_A − x_B| − L = 0 (позиційна похибка)
Ċ = dot((x_A−x_B)/|…|, v_A − v_B) = 0 (похибка швидкості)
Стабілізація Баумгарте (додає пропорційний член):
λ = −(Ċ + β/dt · C) / K
β ∈ [0,1] — стабілізація: зазвичай 0.1–0.3
Розділений імпульс (лише корекція позиції):
Відокремте імпульс корекції швидкості (впливає на швидкість) від
імпульсу корекції позиції (напряму зсуває позицію).
Уникає штучного впорскування енергії від корекції позиції.
| Тип з'єднання | Прибрані ступені свободи | Еквівалент |
|---|---|---|
| Кульове (сферичне) | 3 поступальні | Плече, кульшовий суглоб |
| Шарнір | 3 пост. + 2 обер. | Дверна петля, лікоть |
| Повзун (призматичне) | 3 пост. + 3 обер. − 1 | Поршень, лінійний привід |
| Жорстке | Усі 6 | Зварювання, склеювання |
| Конус (кутове обмеження) | Обмежує кутовий діапазон | Хребет, обмеження плеча |