Для создания реалистичной физики в 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);
Выделение ключевых моментов:
Для синхронизации положения и ориентации объектов 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);
}
Особенности:
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' для обнаружения
взаимодействий.Для больших сцен рекомендуется:
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);
}
Для сложных объектов можно создавать составные коллайдеры:
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-приложений. Использование синхронизации тела и визуального объекта, правильная настройка коллайдеров и оптимизация шагов симуляции обеспечивают реалистичную физику без потери производительности. Составные коллайдеры и кинематические тела расширяют возможности для сложных сцен и анимаций.