Работа с физикой в браузере с использованием Cannon.js часто требует преобразования визуальной геометрии из Three.js в физическую форму, совместимую с симуляцией. Одним из наиболее универсальных способов является использование формы ConvexPolyhedron, которая позволяет описывать объекты с произвольной выпуклой геометрией.
ConvexPolyhedron представляет собой многогранник, определяемый вершинами и гранями:
CANNON.Vec3. Эти точки определяют углы
многогранника.Ключевое ограничение — все вершины должны формировать выпуклый объект. В случае вогнутых форм необходимо разбивать их на несколько ConvexPolyhedron или использовать альтернативные формы (Trimesh).
Three.js предоставляет объект THREE.BufferGeometry, содержащий позиции вершин, нормали и индексы. Для ConvexPolyhedron необходимо:
Извлечь позиции вершин
const positionAttribute = geometry.getAttribute('position');
const vertices = [];
for (let i = 0; i < positionAttribute.count; i++) {
const x = positionAttribute.getX(i);
const y = positionAttribute.getY(i);
const z = positionAttribute.getZ(i);
vertices.push(new CANNON.Vec3(x, y, z));
}Создать грани на основе индексов Если геометрия имеет индексы:
const index = geometry.index;
const faces = [];
for (let i = 0; i < index.count; i += 3) {
faces.push([
index.getX(i),
index.getX(i + 1),
index.getX(i + 2)
]);
}
Для неиндексированной геометрии можно итерировать позиции каждые три вершины как одну грань.
Обеспечить выпуклость ConvexPolyhedron работает
корректно только с выпуклыми формами. Для сложных моделей следует
использовать алгоритмы выпуклой оболочки, например
QuickHull. Three.js предоставляет
THREE.ConvexGeometry, который генерирует выпуклую оболочку
из произвольного набора вершин.
// Предположим, есть THREE.Mesh с геометрией
const geometry = mesh.geometry;
// Получение вершин
const vertices = [];
const positionAttribute = geometry.getAttribute('position');
for (let i = 0; i < positionAttribute.count; i++) {
vertices.push(new CANNON.Vec3(
positionAttribute.getX(i),
positionAttribute.getY(i),
positionAttribute.getZ(i)
));
}
// Получение граней
const faces = [];
if (geometry.index) {
const index = geometry.index;
for (let i = 0; i < index.count; i += 3) {
faces.push([
index.getX(i),
index.getX(i + 1),
index.getX(i + 2)
]);
}
} else {
for (let i = 0; i < vertices.length; i += 3) {
faces.push([i, i + 1, i + 2]);
}
}
// Создание ConvexPolyhedron
const shape = new CANNON.ConvexPolyhedron({
vertices: vertices,
faces: faces
});
Простые формы: если объект можно аппроксимировать кубом, сферой или цилиндром, использование этих примитивов будет быстрее, чем ConvexPolyhedron.
Масштабирование: если Three.js меш имеет масштаб
(mesh.scale), его необходимо применить к вершинам перед
созданием формы.
Центрирование: ConvexPolyhedron работает корректно, если объект центрирован в локальной системе координат. Для смещённых моделей рекомендуется вычитать центр масс:
const center = new CANNON.Vec3();
vertices.forEach(v => center.vadd(v, center));
center.scale(1 / vertices.length, center);
vertices.forEach(v => v.vsub(center, v));После создания формы её можно добавить к телу
CANNON.Body:
const body = new CANNON.Body({
mass: 5, // масса объекта
shape: shape,
position: new CANNON.Vec3(0, 10, 0)
});
world.addBody(body);
ConvexPolyhedron корректно взаимодействует с другими формами Cannon.js, включая плоскости, сферы и другие многогранники. Сложные сцены могут использовать несколько ConvexPolyhedron для более точной симуляции физики, сохраняя производительность.
mesh.updateMatrixWorld(); и использовать
applyMatrix4(mesh.matrixWorld) к каждой вершине.Этот подход обеспечивает точное и эффективное взаимодействие между визуальной геометрией Three.js и физическим движком Cannon.js, сохраняя контроль над формой, точностью и производительностью.