Oimo.js — это легковесная библиотека физического моделирования на JavaScript, ориентированная на реалистичное взаимодействие тел в 3D-пространстве. Она позволяет создавать динамические симуляции с использованием твердых тел, шарниров, пружин и коллайдеров, сохраняя при этом высокую производительность в браузере.
Ключевой элемент любой физической симуляции — мир (World). Он управляет всеми объектами, рассчитывает столкновения и обновляет состояния тел. Создание мира происходит через:
const world = new OIMO.World({
timestep: 1/60,
iterations: 8,
broadphase: 2, // тип алгоритма broadphase
worldscale: 1,
random: true
});
timestep определяет интервал симуляции (обычно 1/60
секунды для плавного обновления).iterations — количество шагов решения ограничений,
влияющее на точность столкновений.broadphase выбирает алгоритм быстрой проверки
потенциальных столкновений.В Oimo.js объекты сцены разделяются на тела (RigidBody) и их коллайдеры (Shape). Тело содержит физические свойства: массу, скорость, положение, а коллайдер определяет форму и размеры.
Пример создания динамического куба:
const box = world.add({
type: "box",
size: [1, 1, 1],
pos: [0, 5, 0],
rot: [0, 0, 0],
move: true,
density: 1
});
type — форма объекта (box,
sphere, cylinder).size — размеры по осям x, y, z.pos и rot задают начальное положение и
ориентацию.move определяет, динамическое тело или
статическое.Статические объекты (move: false) используются как пол,
стены и препятствия. Они не участвуют в динамике, но
влияют на столкновения.
Ключевая задача — обновлять визуальное представление объектов
без блокировки основного потока браузера. Важно, чтобы
физический шаг не выполнялся напрямую внутри рендер-цикла
requestAnimationFrame, иначе может возникнуть задержка
кадров.
Оптимальный подход: использовать раздельные шаги для физики и рендера.
let lastTime = performance.now();
function animate() {
requestAnimationFrame(animate);
const now = performance.now();
const delta = (now - lastTime) / 1000;
lastTime = now;
// Физический шаг с фиксированным timestep
world.step();
// Обновление позиций объектов
boxMesh.position.copy(box.getPosition());
boxMesh.quaternion.copy(box.getQuaternion());
renderer.render(scene, camera);
}
animate();
Принципы такого подхода:
Для крупных сцен целесообразно выносить расчёт физики в Web Worker. Oimo.js позволяет сериализовать состояние тел и отправлять их между потоками.
Пример схемы работы:
world.step().renderer.render.Ключевой момент — минимизация данных, передаваемых между потоками. Передавать лучше массивы чисел (Float32Array), а не объекты с методами.
// В Worker
self.onmess age = function(e) {
const { timestep } = e.data;
world.step(timestep);
const positions = world.bodies.map(b => b.getPosition());
const rotations = world.bodies.map(b => b.getQuaternion());
postMessage({ positions, rotations });
}
Даже при фиксированном timestep частота рендера может отличаться от частоты физического шага. Для устранения рывков используют интерполяцию:
function interpolate(current, previous, alpha) {
return current.clone().lerp(previous, alpha);
}
current — позиция после последнего шага физики.previous — позиция до шага.alpha — дробная часть времени до следующего шага.Такой подход позволяет добиться плавного движения даже при неравномерной частоте кадров.
2 (Sweep and
Prune) подходит для большинства 3D-сцен, ускоряет проверку
столкновений.Oimo.js позволяет отслеживать столкновения через callback на телах:
box.onCollis ion = function(otherBody) {
console.log("Столкновение с:", otherBody.name);
}
Также можно использовать фильтры столкновений, задавая collisionGroup и collisionMask для тел, что экономит ресурсы при большом количестве объектов.
Oimo.js поддерживает шарнирные соединения, пружины и линейные ограничения. Например, чтобы соединить два тела шарниром:
world.addJoint({
type: "joint",
body1: box1,
body2: box2,
pos1: [0, -0.5, 0],
pos2: [0, 0.5, 0],
min: [0, 0, 0],
max: [0, Math.PI/2, 0]
});
Это позволяет создавать реалистичные цепи, механизмы и подвески. Ограничения рассчитываются в том же шаге физики и синхронизируются с рендером по аналогичным принципам.
Эти подходы позволяют использовать Oimo.js в интерактивных 3D-приложениях и играх, сохраняя высокую частоту кадров и точность физики.