Oimo.js — это легковесная физическая библиотека для симуляции твердых
тел в JavaScript. Основной задачей при работе с визуальными объектами
(например, AbstractMesh в Babylon.js) и физикой является
точное соответствие позиции и ориентации визуальной модели положению и
вращению физического тела (RigidBody). Без такой
синхронизации объекты будут визуально «отставать» от физических
расчетов, создавая визуальные артефакты.
Каждый физический объект создается через OIMO.World с
определенной формой, массой и параметрами физики. Для куба, например,
процесс выглядит следующим образом:
// Создание мира с базовыми настройками
const world = new OIMO.World({
timestep: 1/60,
iterations: 8,
broadphase: 2, // 2 — sweep and prune
worldscale: 1,
random: true
});
// Параметры физического тела
const boxConfig = {
type: "box",
size: [1, 1, 1],
pos: [0, 5, 0],
rot: [0, 0, 0],
move: true,
density: 1
};
// Создание RigidBody
const rigidBody = world.add(boxConfig);
// Создание визуальной модели (Babylon.js AbstractMesh)
const boxMesh = BABYLON.MeshBuilder.CreateBox("box", {size: 1}, scene);
boxMesh.position.set(0, 5, 0);
Ключевой момент: RigidBody хранит положение и ориентацию в собственной системе координат, которую нужно преобразовывать в систему координат визуального движка.
Самый простой способ синхронизации — напрямую обновлять свойства
position и rotationQuaternion:
scene.registerBeforeRender(() => {
const pos = rigidBody.getPosition();
const rot = rigidBody.getQuaternion();
boxMesh.position.set(pos.x, pos.y, pos.z);
boxMesh.rotationQuaternion = new BABYLON.Quaternion(rot.x, rot.y, rot.z, rot.w);
});
Особенности:
getPosition() возвращает объект
{x, y, z}.getQuaternion() возвращает кватернион
{x, y, z, w}.Для плавного отображения движения можно использовать интерполяцию между предыдущей и текущей позицией:
let prevPos = rigidBody.getPosition();
let prevRot = rigidBody.getQuaternion();
scene.registerBeforeRender(() => {
const currentPos = rigidBody.getPosition();
const currentRot = rigidBody.getQuaternion();
// Линейная интерполяция позиции
boxMesh.position.lerpTo(
new BABYLON.Vector3(currentPos.x, currentPos.y, currentPos.z),
0.1
);
// Сферическая интерполяция кватернионов
boxMesh.rotationQuaternion = BABYLON.Quaternion.Slerp(
new BABYLON.Quaternion(prevRot.x, prevRot.y, prevRot.z, prevRot.w),
new BABYLON.Quaternion(currentRot.x, currentRot.y, currentRot.z, currentRot.w),
0.1
);
prevPos = currentPos;
prevRot = currentRot;
});
Преимущества: уменьшение резких «рывков» при низкой частоте физического расчета, особенно при быстрых движениях или крупных объектах.
Для объектов с несколькими визуальными элементами
(Compound Mesh) каждый компонент должен иметь собственный
RigidBody или быть частью составного тела
(compound shape). В Oimo.js можно использовать
addCompound:
const compoundBody = world.add({
type: "compound",
move: true,
shapes: [
{ type: "box", size: [1, 1, 1], pos: [0, 0, 0] },
{ type: "sphere", size: [0.5], pos: [0, 1, 0] }
]
});
// Соответствующие mesh
const boxPart = BABYLON.MeshBuilder.CreateBox("boxPart", {size: 1}, scene);
const spherePart = BABYLON.MeshBuilder.CreateSphere("spherePart", {diameter: 1}, scene);
scene.registerBeforeRender(() => {
const pos = compoundBody.getPosition();
const rot = compoundBody.getQuaternion();
boxPart.position.set(pos.x, pos.y, pos.z);
boxPart.rotationQuaternion = new BABYLON.Quaternion(rot.x, rot.y, rot.z, rot.w);
spherePart.position.set(pos.x, pos.y + 1, pos.z);
spherePart.rotationQuaternion = new BABYLON.Quaternion(rot.x, rot.y, rot.z, rot.w);
});
Важно: компоненты составного тела наследуют поведение RigidBody, поэтому их позиции вычисляются относительно центра масс.
rotationQuaternion работают быстрее и точнее, чем через
Euler angles.RigidBody через промежуточный слой,
используя позицию и кватернион.RigidBody можно использовать обратные вызовы
для визуальных эффектов (частицы, деформации).setRotationLock(true, true, true).AbstractMesh и RigidBody работают в разных системах
координат:
const scale = 2; // если масштаб сцены x2
const pos = rigidBody.getPosition();
boxMesh.position.set(pos.x * scale, pos.y * scale, pos.z * scale);
Правильное управление масштабом предотвращает несоответствие физики и визуала.
Система синхронизации AbstractMesh с
RigidBody в Oimo.js позволяет реализовать реалистичную
физику в 3D сценах, управлять сложными составными телами, оптимизировать
производительность и контролировать визуальные эффекты, сохраняя точное
соответствие физическим расчетам.