Итерационный импульсный решатель

Библиотека Oimo.js предоставляет эффективный движок физического моделирования твёрдых тел в среде JavaScript, основой которого является итерационный импульсный решатель (Iterative Impulse Solver). Этот компонент отвечает за корректное вычисление столкновений, ограничения движения и реакций между объектами в реальном времени.


Основные принципы работы

Итерационный импульсный решатель оперирует не с аналитическим решением системы уравнений, а с приближенными решениями, которые постепенно уточняются через несколько итераций. Каждое столкновение и ограничение модели представлено в виде импульса, который применяется к телам для изменения их скорости и угловой скорости.

Формализация импульса

Для двух тел с массами ( m_1 ) и ( m_2 ), сталкивающихся с относительной скоростью ( v_{rel} ), изменение скорости определяется формулой:

[ J = - (1 + e) ]

где:

  • ( J ) — величина импульса,
  • ( e ) — коэффициент восстановления,
  • ( n ) — нормаль столкновения.

Импульс добавляется к линейной и угловой скорости объектов:

[ v_1’ = v_1 + n, v_2’ = v_2 - n]


Итерационный процесс

Решатель выполняет несколько проходов по всем столкновениям и ограничениям. В каждом проходе импульсы корректируют текущие скорости объектов. Такой подход позволяет устранить накопленные ошибки, вызванные множественными пересекающимися контактами.

Ключевые шаги итерационного цикла:

  1. Обнаружение столкновений: генерация списка контактных точек и нормальных векторов.
  2. Вычисление импульсов для каждой контактной пары с учётом массы, скорости и коэффициента трения.
  3. Применение импульсов к линейной и угловой скорости объектов.
  4. Повторение цикла заданное количество итераций или до сходимости.

Количество итераций влияет на точность: 4–10 итераций достаточно для большинства игр, 20 и более требуется для сцен с плотным взаимодействием объектов.


Ограничения и суставы

Oimo.js использует решатель также для поддержки жёстких соединений (joints), таких как шарнирные, пружинные или фиксированные соединения. Каждое соединение создаёт собственное линейное и угловое ограничение, которое в виде импульса корректирует движение объектов.

Пример применения импульса для шарнирного соединения:

[ v_a’ = v_a + n, v_b’ = v_b - n]

где ( n ) направлен вдоль оси ограничения. Для более сложных соединений импульсы могут включать в себя торсионные составляющие, учитывая момент инерции.


Фрикционные импульсы

Фрикция рассчитывается после нормального импульса и зависит от коэффициента трения ( ). Решатель ограничивает касательные импульсы по формуле:

[ |J_t| |J_n|]

где ( J_n ) — нормальный импульс. Это обеспечивает реалистичное скольжение и предотвращает «залипание» объектов при контакте.


Интеграция с временным шагом

Oimo.js использует фиксированный временной шаг ( t ) для расчёта новых скоростей:

[ v_{t+t} = v_t + a t]

Импульсы корректируют уже интегрированные скорости, что позволяет решателю учитывать как внешние силы (гравитацию, силу пользователя), так и внутренние ограничения.


Преимущества итерационного подхода

  • Скорость: решение не требует обращения матриц всей системы, подходит для реального времени.
  • Гибкость: легко расширяется на сцены с большим количеством объектов и разнообразными соединениями.
  • Стабильность: постепенные корректировки предотвращают накопление ошибок при множественных контактах.

Практические рекомендации

  • Использовать умеренное количество итераций, чтобы балансировать точность и производительность.
  • Настраивать коэффициенты восстановления и трения для каждой группы объектов, чтобы контролировать реализм столкновений.
  • Проверять корректность массы и инерции объектов, так как они напрямую влияют на величину импульсов.
  • Для плотных кластеров объектов увеличить итерации, чтобы избежать «протекания» или проскакивания тел сквозь друг друга.

Итерационный импульсный решатель является ядром физического движка Oimo.js, обеспечивая реалистичное взаимодействие объектов, балансируя между точностью и производительностью, и поддерживая сложные механические соединения и контактные сцены.