Oimo.js — это легковесная физическая библиотека для JavaScript, ориентированная на симуляцию твердых тел в реальном времени. Работа с инстансированием и массивами тел требует понимания структуры мира, объектов и их взаимосвязей.
Создание физического мира начинается с инициализации OIMO.World:
const world = new OIMO.World({
timestep: 1/60,
iterations: 8,
broadphase: 2, // 1: brute force, 2: sweep and prune
gravity: [0, -9.8, 0]
});
Ключевые параметры:
timestep — шаг симуляции, влияет на точность и
стабильность.iterations — количество итераций для решения
ограничений.broadphase — метод оптимизации столкновений.gravity — вектор гравитации для мира.Каждое тело в мире создается через world.add с
конфигурацией OIMO.RigidBodyConfig:
const box = world.add({
type: 'box',
size: [1, 1, 1],
pos: [0, 5, 0],
move: true,
density: 1
});
type — форма тела (box,
sphere, cylinder, capsule).size — размеры для коробки или радиус и высота для
цилиндра/капсулы.pos — начальная позиция.move — указывает, подвижное тело или статическое.density — плотность материала.InstancedMesh в сочетании с Oimo.js позволяет оптимизировать рендеринг большого числа одинаковых объектов. В Three.js каждый объект обычно имеет свой геометрический и материал, что сильно нагружает GPU при сотнях и тысячах объектов. InstancedMesh использует одну геометрию и материал для всех экземпляров, меняя только матрицу трансформации.
Создание InstancedMesh:
const count = 1000;
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const mesh = new THREE.InstancedMesh(geometry, material, count);
scene.add(mesh);
count — количество инстансов.mesh.setMatrixAt(index, matrix).Для синхронизации физики с рендерингом создается массив тел:
const bodies = [];
for (let i = 0; i < count; i++) {
const body = world.add({
type: 'box',
size: [1, 1, 1],
pos: [Math.random()*10-5, Math.random()*10, Math.random()*10-5],
move: true,
density: 1
});
bodies.push(body);
}
bodies хранит все физические тела,
соответствующие экземплярам InstancedMesh.function updateInstancedMesh() {
for (let i = 0; i < count; i++) {
const body = bodies[i];
const matrix = new THREE.Matrix4();
matrix.compose(
new THREE.Vector3(body.position.x, body.position.y, body.position.z),
new THREE.Quaternion(body.rotation.x, body.rotation.y, body.rotation.z, body.rotation.w),
new THREE.Vector3(1, 1, 1)
);
mesh.setMatrixAt(i, matrix);
}
mesh.instanceMatrix.needsUpdate = true;
}
При работе с тысячами объектов важно учитывать производительность:
Пример создания пола и стен:
world.add({
type: 'box',
size: [50, 1, 50],
pos: [0, -0.5, 0],
move: false
});
world.add({
type: 'box',
size: [1, 10, 50],
pos: [-25, 5, 0],
move: false
});
Для сложных сцен удобно группировать тела по логике:
const stacks = [];
for (let j = 0; j < 10; j++) {
const stack = [];
for (let i = 0; i < 10; i++) {
const body = world.add({
type: 'box',
size: [1, 1, 1],
pos: [i, j, 0],
move: true,
density: 1
});
stack.push(body);
}
stacks.push(stack);
}
Интеграция с Three.js обычно выполняется через цикл рендера:
function animate() {
requestAnimationFrame(animate);
world.step();
updateInstancedMesh();
renderer.render(scene, camera);
}
animate();
world.step() — продвигает симуляцию на один шаг
времени.updateInstancedMesh() — синхронизирует физику с
визуализацией.Oimo.js позволяет добавлять и удалять тела в процессе симуляции:
// Добавление нового тела
const newBody = world.add({
type: 'sphere',
size: [0.5],
pos: [0, 10, 0],
move: true,
density: 1
});
bodies.push(newBody);
// Удаление тела
world.remove(bodies[0]);
bodies.splice(0, 1);
Массивы тел позволяют реализовать массовые эффекты:
function applyExplosion(center, radius, force) {
bodies.forEach(body => {
const dir = new OIMO.Vec3(body.position.x - center.x, body.position.y - center.y, body.position.z - center.z);
const distance = dir.length();
if (distance < radius) {
dir.normalize();
body.applyImpulse(dir.scale(force * (1 - distance / radius)));
}
});
}
Применение этих подходов обеспечивает производительную, масштабируемую и гибкую симуляцию физических сцен с тысячами объектов в Oimo.js и Three.js.