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(); // возвращает текущую ориентацию
Особенности:
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 предлагает следующие подходы:
timestep снижает точность, но повышает
производительность.box.sleep(); // перевод тела в спящий режим
box.wakeUp(); // пробуждение при взаимодействии
В Oimo.js реализован принцип islands simulation — объединение взаимосвязанных тел в отдельные группы для обработки столкновений. Это позволяет:
Каждый остров обрабатывается отдельно, а связи между островами проверяются только при контакте. Это особенно важно для группового засыпания, когда целые участки сцены могут быть переведены в спящий режим без проверки каждого объекта по отдельности.
world.step();
world.updateSleep(); // автоматическое управление спящими островами
Принцип работы:
Oimo.js не имеет встроенного рендеринга, поэтому часто используется совместно с Three.js или Babylon.js. Основные шаги:
getPosition() и getQuaternion().function animate() {
requestAnimationFrame(animate);
world.step();
mesh.position.copy(box.getPosition());
mesh.quaternion.copy(box.getQuaternion());
renderer.render(scene, camera);
}
Такой подход обеспечивает синхронность физики и графики, позволяя создавать реалистичные симуляции объектов, падения и групповых взаимодействий.
Эти возможности делают Oimo.js мощным инструментом для физического моделирования динамических сцен, от простых падающих объектов до сложных механических систем с множеством взаимосвязанных тел.