Интеграция rapier.js

Для создания реалистичной физики в 3D-сценах на Three.js необходим движок физики. Rapier.js представляет собой современный физический движок с поддержкой как твердотельной, так и динамической симуляции объектов. Интеграция этих двух библиотек позволяет комбинировать визуальное представление с точной физикой.

Установка и подключение

Установка выполняется через npm:

npm install three @dimforge/rapier3d

Импорт в проект:

import * as THREE from 'three';
import RAPIER from '@dimforge/rapier3d';

Создание физического мира

Физический мир в Rapier управляется объектом World, который отвечает за гравитацию, столкновения и шаг симуляции.

const gravity = { x: 0, y: -9.81, z: 0 };
const world = new RAPIER.World(gravity);

Ключевые параметры:

  • gravity — вектор гравитации.
  • World — основной контейнер для всех физически симулируемых тел.

Создание тел и коллайдеров

В Rapier существуют два типа объектов: RigidBody (тело) и Collider (форма столкновения). Тело может быть динамическим, статическим или кинематическим.

const rigidBodyDesc = RAPIER.RigidBodyDesc.dynamic()
    .setTranslation(0, 5, 0);
const body = world.createRigidBody(rigidBodyDesc);

const colliderDesc = RAPIER.ColliderDesc.cuboid(1, 1, 1);
const collider = world.createCollider(colliderDesc, body.handle);

Выделение ключевых моментов:

  • RigidBodyDesc.dynamic() создаёт подвижное тело.
  • ColliderDesc.cuboid задаёт форму столкновения, совпадающую с визуальной моделью.
  • body.handle связывает коллайдер с телом.

Связь с Three.js

Для синхронизации положения и ориентации объектов Three.js с телами Rapier используется шаг симуляции и обновление матрицы объекта.

const geometry = new THREE.BoxGeometry(2, 2, 2);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

function updatePhysics(deltaTime) {
    world.step(deltaTime);
    const position = body.translation();
    const rotation = body.rotation();
    
    mesh.position.set(position.x, position.y, position.z);
    mesh.quaternion.set(rotation.x, rotation.y, rotation.z, rotation.w);
}

Особенности:

  • world.step(deltaTime) выполняет симуляцию физики.
  • Используется синхронизация через position и quaternion для точного соответствия 3D-модели физике.

Работа с столкновениями

Rapier позволяет реагировать на столкновения через events или проверку контактных точек.

world.registerEventQueue();

function handleCollisions() {
    const events = world.events;
    for (let i = 0; i < events.length; i++) {
        const e = events[i];
        if (e.type === 'contact') {
            console.log(`Столкновение между ${e.collider1} и ${e.collider2}`);
        }
    }
}

Ключевые моменты:

  • Регистрация очереди событий через registerEventQueue().
  • Обработка типа события 'contact' для обнаружения взаимодействий.

Оптимизация производительности

Для больших сцен рекомендуется:

  • Использовать сплошные статические тела для окружающей среды.
  • Ограничивать число динамических тел.
  • Применять sleeping для неподвижных объектов.
  • Делать шаг симуляции с фиксированным timestep, например 1/60, для стабильности.
const fixedTimeStep = 1 / 60;
let accumulator = 0;

function animate(deltaTime) {
    accumulator += deltaTime;
    while (accumulator >= fixedTimeStep) {
        world.step(fixedTimeStep);
        accumulator -= fixedTimeStep;
    }
    updateMeshPositions();
    renderer.render(scene, camera);
}

Использование Compound Colliders

Для сложных объектов можно создавать составные коллайдеры:

const bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(0, 2, 0);
const compoundBody = world.createRigidBody(bodyDesc);

const box1 = RAPIER.ColliderDesc.cuboid(1, 1, 1);
const box2 = RAPIER.ColliderDesc.cuboid(0.5, 0.5, 0.5).setTranslation(0, 1.5, 0);

world.createCollider(box1, compoundBody.handle);
world.createCollider(box2, compoundBody.handle);

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

Интеграция с анимациями

Физика Rapier и анимации Three.js могут работать вместе, если кинематические тела обновляются вручную:

const kinematicBody = world.createRigidBody(
    RAPIER.RigidBodyDesc.kinematicPosition()
);

function animateCharacter(deltaTime) {
    const t = performance.now() * 0.001;
    const newPos = new THREE.Vector3(Math.sin(t) * 5, 2, 0);
    kinematicBody.setTranslation(newPos, true);

    mesh.position.copy(newPos);
}

Ключевой момент: кинематические тела управляются напрямую и могут взаимодействовать с динамическими объектами.

Заключение по методологии

Интеграция Rapier.js и Three.js создаёт мощный инструмент для разработки интерактивных 3D-приложений. Использование синхронизации тела и визуального объекта, правильная настройка коллайдеров и оптимизация шагов симуляции обеспечивают реалистичную физику без потери производительности. Составные коллайдеры и кинематические тела расширяют возможности для сложных сцен и анимаций.