Библиотека Oimo.js представляет собой физический движок на JavaScript, оптимизированный для симуляции твёрдого тела, столкновений и динамики объектов в 3D-сценах. Одной из ключевых задач при интеграции Oimo.js с графическими движками, такими как Three.js, является корректная синхронизация физических тел с визуальными объектами.
В Oimo.js каждый объект физики создаётся как экземпляр
Oimo.Body. Этот объект хранит массу,
геометрию, положение, ориентацию и параметры столкновений. Для
визуального представления используется отдельный объект (например,
THREE.Mesh), и необходимо регулярно обновлять его
трансформацию в соответствии с положением и вращением физического
тела.
Для упрощения синхронизации создаётся класс-обёртка, объединяющий физическое тело и визуальный объект. Основная структура класса включает:
class PhysicsObject {
constructor(mesh, body) {
this.mesh = mesh; // Визуальный объект (Three.js Mesh)
this.body = body; // Физическое тело (Oimo.Body)
}
upd ate() {
// Синхронизация позиции
const pos = this.body.getPosition();
this.mesh.position.se t(pos.x, pos.y, pos.z);
// Синхронизация вращения
const rot = this.body.getQuaternion();
this.mesh.quaternion.set(rot.x, rot.y, rot.z, rot.w);
}
applyForce(force) {
// Применение силы к физическому телу
this.body.applyForce(force);
}
applyImpulse(impulse) {
// Применение мгновенного импульса
this.body.applyImpulse(impulse);
}
}
Ключевые моменты:
update() вызывается каждый кадр
после шага физического симулятора, обеспечивая соответствие позиции и
ориентации визуального объекта данным физики.applyForce() и
applyImpulse() дают возможность управлять
объектами через физику, не нарушая консистентности.Oimo.js предоставляет различные формы тел через
Oimo.BoxGeometry, Oimo.SphereGeometry,
Oimo.CylinderGeometry и т.д. При создании тела важно
правильно настроить массу, тип динамики и
столкновения:
const bodyConfig = {
type: 'box', // форма: box, sphere, cylinder
size: [1, 1, 1], // размеры по осям x, y, z
pos: [0, 5, 0], // начальная позиция
rot: [0, 0, 0], // начальная ориентация
move: true, // динамическое тело
density: 1 // плотность
};
const boxBody = world.add(bodyConfig);
const boxMesh = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({ color: 0x00ff00 })
);
const physicsBox = new PhysicsObject(boxMesh, boxBody);
В типичном рендер-цикле:
function animate() {
requestAnimationFrame(animate);
// Шаг физики
world.step();
// Обновление всех объектов
physicsObjects.forEach(obj => obj.update());
renderer.render(scene, camera);
}
Рекомендации по производительности:
Oimo.Vec3 и Oimo.Quat для
локальных вычислений и уменьшения количества временных объектов.Можно добавить методы для более сложных взаимодействий:
setPosition(x, y, z) – мгновенная
установка позиции без учёта текущей скорости.setRotation(x, y, z, w) – установка
ориентации через кватернион.followTarget(targetMesh) – копирование
позиции и вращения другого объекта, полезно для закрепления визуальных
элементов.resetVelocity() – сброс линейной и
угловой скорости при необходимости остановки объекта.Пример расширения:
class PhysicsObjectExtended extends PhysicsObject {
setPosition(x, y, z) {
this.body.setPosition(x, y, z);
this.update();
}
resetVelocity() {
this.body.setLinearVelocity({ x: 0, y: 0, z: 0 });
this.body.setAngularVelocity({ x: 0, y: 0, z: 0 });
}
}
Для составных объектов, состоящих из нескольких тел (например, робот
или транспорт), создаётся контейнерный класс,
управляющий коллекцией PhysicsObject. Такой подход
позволяет:
Пример:
class PhysicsGroup {
constructor(objects = []) {
this.objects = objects;
}
update() {
this.objects.forEach(obj => obj.update());
}
applyForceToAll(force) {
this.objects.forEach(obj => obj.applyForce(force));
}
add(obj) {
this.objects.push(obj);
}
}
setQuaternion(x, y, z, w) у графических объектов.mesh.position и mesh.quaternion должны
быть синхронизированы после каждого вызова
world.step().Эта структура утилитарного класса-обёртки обеспечивает прозрачное и безопасное управление синхронизацией физики и графики, позволяя строить сложные интерактивные сцены с использованием Oimo.js.