Чисельні методи — як фізика стає кодом

Закони Ньютона описують, як сили змінюють швидкість. Інтегрування Ейлера, Рунге-Кутта 4-го порядку та інтегрування Верле — три алгоритми, що перетворюють ці неперервні рівняння на дискретний, покроковий рух на екрані. Ось що вони собою являють і чому варто обрати кожен із них.

Проблема: комп'ютери не вміють робити числення нескінченно малих

Фізичні рівняння описують зміну через похідні: швидкість — це швидкість зміни положення, прискорення — швидкість зміни швидкості. У неперервній математиці це числення нескінченно малих. У комп'ютері час потрібно розбити на маленькі дискретні кроки (що називаються кроком за часом, Δt). Питання в тому: наскільки точно ми можемо наблизити неперервний рух цими крихітними кроками?

Відповідь залежить від методу інтегрування. Поганий метод дрейфує з часом — енергія штучно накопичується, доки симульовані пружини не вибухають. Хороший метод утримує повну енергію системи майже сталою протягом тисяч кроків.

Ключове розуміння: кожна фізична симуляція на цьому сайті виконує один із цих трьох методів (або їхню комбінацію) сотні разів на секунду. Вибір безпосередньо впливає на те, чи залишиться маятник стабільним протягом 10 хвилин, чи почне коливатися до нескінченності вже через 30 секунд.

Три методи

Інтегрування Ейлера
⚡ Найшвидший

Найпростіший метод: використати поточну швидкість, щоб оцінити, де ви опинитеся через Δt, потім оновити. Одне обчислення функції на крок. Швидко, але накопичує похибку — енергія повільно зростає, змушуючи орбіти розкручуватися назовні, а пружини — вибухати.

// Явний метод Ейлера
position += velocity * dt;
velocity += acceleration * dt;
Використовується для: іскор частинок, візуальних ефектів, де точність не має значення
Рунге-Кутта 4-го порядку (RK4)
🎯 Найточніший

Бере чотири оцінки похідної в межах кожного кроку за часом і обчислює зважене середнє. Значно краща точність, ніж у Ейлера, лише за 4-кратної вартості. Стандартний вибір для балістики, орбітальної механіки та хімічних симуляцій.

// Спрощений RK4 для положення/швидкості
const k1 = f(t,  state);
const k2 = f(t + dt/2, state + k1*dt/2);
const k3 = f(t + dt/2, state + k2*dt/2);
const k4 = f(t + dt,   state + k3*dt);
state += (k1 + 2*k2 + 2*k3 + k4) * dt/6;
Використовується для: орбітальних симуляцій, балістики, дифузії ліків, стовпів рідини
Інтегрування Верле / метод «жаби»
🔒 Найстабільніший

Хитрий трюк: швидкість і положення зсунуті на половину кроку за часом. Це утримує повну енергію системи майже сталою протягом дуже довгих симуляцій — ідеально для молекулярної динаміки й тканини, де симуляція має працювати нескінченно. Використовується всередині Cannon-es (фізичного рушія на цьому сайті).

// Швидкісний метод Верле
posNext = pos + vel*dt + 0.5*acc*dt*dt;
velNext = vel + 0.5*(acc + accNext)*dt;
Використовується для: тканини, мотузки, молекулярної динаміки, фізики твердого тіла

Які симуляції який метод використовують?

Патерн фіксованого кроку за часом

Ще одне ускладнення: монітори оновлюються з частотою 60 Гц, але кадри не завжди рендеряться рівно за 1/60 секунди. Якщо крок фізики за часом дорівнює кроку рендерингу, повільний кадр означає великий Δt, що може змусити жорсткі пружини вибухнути.

Розв'язок — використаний у всіх складних симуляціях тут — фіксований крок за часом з накопиченням:

const FIXED_DT = 1 / 120; // фізика 120 Гц
let accumulator = 0;

function tick(realDt) {
  accumulator += realDt;
  while (accumulator >= FIXED_DT) {
    physics.step(FIXED_DT);
    accumulator -= FIXED_DT;
  }
  render(); // виконується з частотою екрана
}

Фізика завжди просувається однаковими, безпечними кроками, незалежно від того, скільки часу займає рендеринг. Рендер просто малює те, де зараз перебуває фізика.