Острова симуляции и групповое засыпание

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

Главными сущностями Oimo.js являются мир (World), тела (RigidBody) и коллайдеры (Shape). Мир управляет всей физикой сцены, включая гравитацию, шаг интеграции и обработку столкновений. Тела представляют объекты, подчиняющиеся законам физики, а коллайдеры определяют их геометрию для вычисления столкновений.


Создание мира и настройка параметров

import * as OIMO from 'oimo';

const world = new OIMO.World({
    timestep: 1/60,          // шаг симуляции
    iterations: 8,           // количество итераций для устойчивости
    broadphase: 2,           // метод предварительного обнаружения столкновений
    gravity: [0, -9.8, 0]   // вектор гравитации
});

Ключевые параметры мира:

  • timestep — определяет частоту обновления физики; малые значения повышают точность, большие — производительность.
  • iterations — количество итераций решения ограничений; большее значение улучшает устойчивость сложных систем.
  • broadphase — алгоритм предварительного поиска столкновений. Значение 2 соответствует оптимизированному Sweep and Prune.
  • gravity — глобальная сила гравитации, задается в виде вектора [x, y, z].

Создание тел и формирование коллайдеров

Тело создается через объект RigidBody, которому можно присвоить тип динамики: dynamic, static или kinematic.

const box = world.add({
    type: 'box',
    size: [2, 2, 2],
    pos: [0, 5, 0],
    rot: [0, 0, 0],
    move: true,      // true для dynamic
    density: 1       // плотность материала
});

Параметры тел:

  • size — размеры тела по осям X, Y, Z.
  • pos — начальная позиция в мире.
  • rot — начальный угол поворота.
  • move — указывает на динамическое поведение: true для динамических, false для статических.
  • density — плотность материала, влияет на массу тела через объём: mass = density * volume.

Коллайдеры автоматически создаются на основе типа тела, но можно использовать сложные формы, комбинируя составные меши (Compound Shapes):

const compoundBody = world.add({
    type: 'compound',
    shapes: [
        { type: 'box', size: [1, 1, 1], pos: [0, 0, 0] },
        { type: 'sphere', size: [0.5], pos: [0, 1, 0] }
    ],
    pos: [2, 5, 0],
    move: true
});

Симуляция столкновений

Oimo.js использует алгоритм GJK (Gilbert–Johnson–Keerthi) + EPA (Expanding Polytope Algorithm) для вычисления столкновений. Эти методы позволяют определять точки контакта и нормали поверхности для точного расчета реакции тел.

world.step();

box.getPosition(); // возвращает текущие координаты тела
box.getQuaternion(); // возвращает текущую ориентацию

Особенности:

  • Для динамических тел точные реакции столкновений обеспечивают реалистичное поведение при падении, отскоках и скольжении.
  • Статические тела не изменяют положение при столкновениях, но влияют на динамические.
  • Kinematic-тела управляются вручную, но участвуют в столкновениях, передавая силы динамическим объектам.

Связки и ограничения

Oimo.js поддерживает несколько видов ограничений, позволяющих создавать сложные механизмы:

  • distanceJoint — сохраняет расстояние между двумя точками.
  • hingeJoint — реализует вращение вокруг оси, используется для дверей и рычагов.
  • sliderJoint — позволяет скользить вдоль одной оси.

Пример создания шарнира:

const hinge = world.add({
    type: 'joint',
    jointType: 'hinge',
    bodyA: box,
    bodyB: compoundBody,
    pos: [1, 5, 0],
    axis: [0, 1, 0]
});

Особенности использования:

  • Параметры axis и pos определяют точку соединения и ось вращения.
  • Можно задавать limits для ограничения угла движения.
  • Поддерживаются мягкие ограничения с параметрами spring и damping.

Оптимизация симуляции

Для больших сцен с множеством объектов Oimo.js предлагает следующие подходы:

  1. Broadphase фильтры — уменьшение числа проверок столкновений за счет пространственного разбиения.
  2. Sleep режим — объекты, которые не двигаются длительное время, переводятся в спящий режим, снижая нагрузку.
  3. Составные тела — объединение нескольких мелких объектов в один для уменьшения числа столкновений.
  4. Настройка шагов интеграции — увеличение timestep снижает точность, но повышает производительность.
box.sleep(); // перевод тела в спящий режим
box.wakeUp(); // пробуждение при взаимодействии

Работа с островами симуляции

В Oimo.js реализован принцип islands simulation — объединение взаимосвязанных тел в отдельные группы для обработки столкновений. Это позволяет:

  • Уменьшить вычислительные затраты, отделяя независимые группы объектов.
  • Повышать стабильность сложных систем из множества тел.
  • Эффективно обрабатывать цепные реакции, например, падение кирпичей или взаимодействие объектов в контейнерах.

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

world.step();
world.updateSleep(); // автоматическое управление спящими островами

Принцип работы:

  • Все тела, не испытывающие значительных сил, объединяются в острова.
  • Если тело в острове активируется, весь остров пробуждается.
  • Позволяет эффективно симулировать сцены с сотнями динамических объектов.

Взаимодействие с визуализацией

Oimo.js не имеет встроенного рендеринга, поэтому часто используется совместно с Three.js или Babylon.js. Основные шаги:

  1. Создать тела в Oimo.js.
  2. Для каждого тела создать соответствующий меш в графическом движке.
  3. На каждом кадре обновлять позицию и ориентацию мешей через getPosition() и getQuaternion().
function animate() {
    requestAnimationFrame(animate);
    world.step();

    mesh.position.copy(box.getPosition());
    mesh.quaternion.copy(box.getQuaternion());

    renderer.render(scene, camera);
}

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


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