Работа с инстансированием: InstancedMesh и массив тел

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 и массив тел

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;
}

Массовое создание тел и оптимизация

При работе с тысячами объектов важно учитывать производительность:

  1. Использование InstancedMesh — минимизирует нагрузку на GPU.
  2. Массив тел — оптимизация управления, позволяет обновлять позиции за один проход.
  3. Ограничение итераций Oimo.js — уменьшает нагрузку CPU, важно балансировать точность и скорость.
  4. Статические объекты — добавление пола и стен как статических тел снижает количество расчетов столкновений.

Пример создания пола и стен:

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);
  • Важно корректно обновлять массив тел и InstancedMesh.
  • Для InstancedMesh удаление можно реализовать через маскирование экземпляров или перераспределение индексов.

Применение физических эффектов к массивам тел

Массивы тел позволяют реализовать массовые эффекты:

  • Гравитационные центры — силы, притягивающие все тела к точке.
  • Взрывы — применение импульсов ко всем объектам в радиусе.
  • Коллизии с динамическими объектами — реагирование на движение одного объекта сразу по всему массиву.
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)));
        }
    });
}
  • Использование массивов делает массовые операции эффективными и структурированными.

Итоги по работе с InstancedMesh и массивами тел

  • InstancedMesh уменьшает нагрузку на GPU при большом числе объектов.
  • Массив тел позволяет эффективно управлять физикой и синхронизацией с визуализацией.
  • Группировка и динамическое управление телами упрощает сложные симуляции.
  • Массовые эффекты становятся простыми благодаря организации данных в массивы.

Применение этих подходов обеспечивает производительную, масштабируемую и гибкую симуляцию физических сцен с тысячами объектов в Oimo.js и Three.js.