Для интеграции физического движка cannon-es в проект на Three.js необходимо установить пакет через npm:
npm install three cannon-es
Импорт в модуле ES6 выполняется следующим образом:
import * as THREE from 'three';
import * as CANNON from 'cannon-es';
Создание сцены, камеры и рендерера Three.js остаётся стандартным:
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 5, 10);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
Физический мир CANNON.World отвечает за симуляцию. Основные параметры:
gravity — гравитация вектором.broadphase — алгоритм широкого поиска
столкновений.solver — система решения контактов.Пример:
const world = new CANNON.World({
gravity: new CANNON.Vec3(0, -9.82, 0),
broadphase: new CANNON.SAPBroadphase(),
solver: new CANNON.GSSolver()
});
Для стабильности можно увеличить точность интеграции:
world.defaultContactMaterial.contactEquationStiffness = 1e7;
world.defaultContactMaterial.contactEquationRelaxation = 3;
Cannon-es использует Body и
Shape для представления физических объектов. Типичные
формы: Box, Sphere, Plane,
Cylinder.
Пример создания пола и куба:
// Физический пол
const groundBody = new CANNON.Body({
mass: 0, // масса 0 = статическое тело
shape: new CANNON.Plane(),
position: new CANNON.Vec3(0, 0, 0)
});
groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0);
world.addBody(groundBody);
// Физический куб
const boxShape = new CANNON.Box(new CANNON.Vec3(1, 1, 1));
const boxBody = new CANNON.Body({
mass: 5,
shape: boxShape,
position: new CANNON.Vec3(0, 5, 0)
});
world.addBody(boxBody);
Для визуализации физики используется объект THREE.Mesh с геометрией и материалом. Объект привязывается к телу физического движка в анимационном цикле:
// Three.js-меш
const boxGeometry = new THREE.BoxGeometry(2, 2, 2);
const boxMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 });
const boxMesh = new THREE.Mesh(boxGeometry, boxMaterial);
scene.add(boxMesh);
// Синхронизация в анимации
function animate() {
requestAnimationFrame(animate);
world.step(1/60); // шаг физики
// Синхронизация позиции и ориентации
boxMesh.position.copy(boxBody.position);
boxMesh.quaternion.copy(boxBody.quaternion);
renderer.render(scene, camera);
}
animate();
Cannon-es поддерживает события столкновений через
addEventListener:
boxBody.addEventListener('collide', (event) => {
console.log('Столкновение с объектом:', event.body);
});
Каждое событие содержит информацию о другом теле и точке контакта. Это позволяет реализовать эффектные реакции на столкновения, например, изменение цвета или проигрывание звука.
Для создания соединённых объектов используются Constraints:
CANNON.HingeConstraint — шарнирное соединение.CANNON.DistanceConstraint — фиксация расстояния.CANNON.LockConstraint — полная блокировка
относительного движения.Пример шарнирного соединения:
const hinge = new CANNON.HingeConstraint(boxBody, groundBody, {
pivotA: new CANNON.Vec3(0, -1, 0),
axisA: new CANNON.Vec3(0, 0, 1),
pivotB: new CANNON.Vec3(0, 0, 0),
axisB: new CANNON.Vec3(0, 0, 1)
});
world.addConstraint(hinge);
Для реалистичного отображения рекомендуется использовать THREE.MeshStandardMaterial или MeshPhysicalMaterial с источниками света:
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 10, 7.5);
scene.add(directionalLight);
Физика и освещение работают отдельно, поэтому важно синхронизировать позиции и кватернионы объектов Three.js с телами Cannon-es при каждом кадре.
SAPBroadphase
для статичных или слабо подвижных сцен.world.step держать фиксированным
(например, 1/60).const helper = new THREE.BoxHelper(boxMesh, 0x00ff00);
scene.add(helper);
const objects = [];
objects.push({ mesh: boxMesh, body: boxBody });
objects.forEach(obj => {
obj.mesh.position.copy(obj.body.position);
obj.mesh.quaternion.copy(obj.body.quaternion);
});
dat.GUI)
позволяет менять массу, гравитацию или коэффициент трения в реальном
времени.Для нестандартных объектов можно использовать
CANNON.ConvexPolyhedron:
const vertices = [
new CANNON.Vec3(-1, -1, -1),
new CANNON.Vec3(1, -1, -1),
new CANNON.Vec3(1, 1, -1),
new CANNON.Vec3(-1, 1, -1),
new CANNON.Vec3(-1, -1, 1),
new CANNON.Vec3(1, -1, 1),
new CANNON.Vec3(1, 1, 1),
new CANNON.Vec3(-1, 1, 1)
];
const faces = [
[0,1,2,3],
[4,5,6,7],
[0,1,5,4],
[2,3,7,6],
[0,3,7,4],
[1,2,6,5]
];
const shape = new CANNON.ConvexPolyhedron({ vertices, faces });
const body = new CANNON.Body({ mass: 5, shape });
world.addBody(body);
Эта методика позволяет интегрировать любые трехмерные модели, экспортированные из редакторов, в физическую симуляцию.