Использование Oimo.js в контексте
Web Worker позволяет перенести все вычисления физического
движка в отдельный поток, освобождая основной поток браузера от
интенсивных расчётов и обеспечивая плавность визуализации. Этот подход
особенно эффективен для сложных симуляций с большим количеством тел.
Oimo.js может быть использован как модуль через
importScripts или в виде ES-модуля. Для классического
Worker:
// worker.js
importScripts('path/to/oimo.min.js');
// Создание мира
const world = new OIMO.World({
timestep: 1/60,
iterations: 8,
broadphase: 2, // 1: brute force, 2: sweep & prune, 3: volume tree
worldscale: 1,
random: true,
info: false
});
Для использования ES-модулей (type="module"):
// worker-module.js
import * as OIMO from './oimo.module.js';
const world = new OIMO.World({
timestep: 1/60,
iterations: 8,
broadphase: 2,
worldscale: 1,
random: true,
info: false
});
Oimo.js работает с объектами RigidBody, которые обладают
формами (Shape) и физическими свойствами. В Worker
инициализация тел выглядит следующим образом:
// Создание тела куба
const box = world.add({
type: "box",
size: [1, 1, 1],
pos: [0, 5, 0],
rot: [0, 0, 0],
move: true,
density: 1,
friction: 0.5,
restitution: 0.3
});
// Создание статической плоскости
world.add({
type: "box",
size: [10, 1, 10],
pos: [0, 0, 0],
move: false
});
Ключевые параметры:
type: "box", "sphere",
"cylinder".size: массив размеров
[width, height, depth] для коробок.pos: координаты [x, y, z].rot: поворот в радианах [x, y, z].move: подвижность тела (true для
динамического, false для статического).density, friction,
restitution: физические свойства материала.Работа физического мира требует регулярного обновления состояния тел.
В Worker это организуется через setInterval или
requestAnimationFrame с использованием
postMessage для передачи состояния обратно в основной
поток:
function upd ate() {
world.step();
const bodiesState = world.rigidBodies.map(body => ({
id: body.id,
position: body.getPosition(),
rotation: body.getQuaternion()
}));
postMessage({ type: 'upd ate', bodies: bodiesState });
}
setInterval(update, 1000/60); // Обновление 60 раз в секунду
Worker не имеет доступа к DOM, поэтому все визуальные данные должны
передаваться через postMessage. В основном потоке:
const worker = new Worker('worker.js');
worker.onmess age = (event) => {
const data = event.data;
if (data.type === 'update') {
data.bodies.forEach(body => {
const mesh = scene.getObjectById(body.id);
mesh.position.se t(...body.position);
mesh.quaternion.se t(...body.rotation);
});
}
};
Использование структурированных клонов или
Transferable Objects позволяет снизить нагрузку при
передаче больших массивов данных, особенно при работе с сотнями тел.
Oimo.js поддерживает Constraints (соединения) между телами. В Worker добавление соединений выполняется аналогично добавлению тел:
const joint = world.add({
type: 'jointDistance',
body1: box1,
body2: box2,
minDistance: 1,
maxDistance: 2,
collideConnected: false
});
Основные типы соединений:
jointDistance — поддерживает фиксированное
расстояние.jointHinge — реализует шарнирное вращение.jointSlider — ограничивает движение вдоль оси.2 или
3 для крупных сцен.postMessage — передавать состояние
не чаще 60 Гц.Float32Array для буферов.random: true для лучшего распределения
столкновений при динамических телах.importScripts('oimo.min.js');
const world = new OIMO.World({ timestep: 1/60, iterations: 8, broadphase: 2 });
const ground = world.add({ type: "box", size: [20, 1, 20], pos: [0, 0, 0], move: false });
const cube = world.add({ type: "box", size: [1, 1, 1], pos: [0, 5, 0], move: true, density: 1 });
setInterval(() => {
world.step();
postMessage({
bodies: world.rigidBodies.map(b => ({
id: b.id,
pos: b.getPosition(),
rot: b.getQuaternion()
}))
});
}, 1000/60);
Этот подход обеспечивает полное разделение вычислений и визуализации, делает физический движок Oimo.js максимально производительным в браузере, а Worker — эффективным инструментом для масштабируемых симуляций.