Визуализация AABB и форм вручную

Cannon.js — это физический движок для JavaScript, предназначенный для симуляции твердого тела, столкновений и динамики объектов в 3D-пространстве. Одним из ключевых инструментов при отладке физических сцен является визуализация AABB (Axis-Aligned Bounding Box) и самих форм. AABB представляет собой прямоугольный параллелепипед, выровненный по осям координат, который полностью охватывает объект. Он используется для ускорения вычислений столкновений и для диагностики неправильного поведения физических тел.

В Cannon.js каждый объект физического мира представлен экземпляром класса Body, а его форма — экземпляром класса Shape. Для визуализации можно использовать как готовые библиотеки, например, three.js, так и кастомное создание геометрий.


Получение и отображение AABB

Каждое тело в Cannon.js имеет метод updateAABB(), который вычисляет актуальные границы тела. После этого можно получить свойства aabb.lowerBound и aabb.upperBound, которые задают минимальные и максимальные координаты параллелепипеда.

body.updateAABB();
const lower = body.aabb.lowerBound;
const upper = body.aabb.upperBound;

Эти координаты можно использовать для построения каркаса AABB с помощью линий:

const geometry = new THREE.BoxGeometry(
    upper.x - lower.x,
    upper.y - lower.y,
    upper.z - lower.z
);

const edges = new THREE.EdgesGeometry(geometry);
const material = new THREE.LineBasicMaterial({ color: 0xff0000 });
const wireframe = new THREE.LineSegments(edges, material);

wireframe.position.set(
    (upper.x + lower.x) / 2,
    (upper.y + lower.y) / 2,
    (upper.z + lower.z) / 2
);

scene.add(wireframe);

Ключевой момент: для динамических тел нужно обновлять позицию AABB каждый кадр после симуляции физики, иначе визуализация будет отставать от реального положения тела.


Визуализация форм вручную

Cannon.js предоставляет различные типы форм: Box, Sphere, Cylinder, ConvexPolyhedron, Trimesh. Для ручной визуализации формы можно использовать аналогичную геометрию в three.js, синхронизируя позицию и ориентацию тела.

Пример визуализации Box:

const boxShape = new CANNON.Box(new CANNON.Vec3(1, 1, 1));
const boxBody = new CANNON.Body({ mass: 1 });
boxBody.addShape(boxShape);

const boxGeometry = new THREE.BoxGeometry(2, 2, 2);
const boxMaterial = new THREE.MeshNormalMaterial();
const boxMesh = new THREE.Mesh(boxGeometry, boxMaterial);

scene.add(boxMesh);

// В анимационном цикле
function upd ate() {
    world.step(1/60);

    boxMesh.position.copy(boxBody.position);
    boxMesh.quaternion.copy(boxBody.quaternion);

    requestAnimationFrame(upd ate);
}
update();

Пример визуализации Sphere:

const sphereShape = new CANNON.Sphere(1);
const sphereBody = new CANNON.Body({ mass: 1 });
sphereBody.addShape(sphereShape);

const sphereGeometry = new THREE.SphereGeometry(1, 16, 16);
const sphereMaterial = new THREE.MeshNormalMaterial();
const sphereMesh = new THREE.Mesh(sphereGeometry, sphereMaterial);

scene.add(sphereMesh);

// В анимационном цикле
sphereMesh.position.copy(sphereBody.position);
sphereMesh.quaternion.copy(sphereBody.quaternion);

Для сложных форм типа ConvexPolyhedron или Trimesh требуется конструировать геометрию вручную, перебирая вершины и индексы:

const vertices = convexShape.vertices.map(v => new THREE.Vector3(v.x, v.y, v.z));
const geometry = new THREE.BufferGeometry().setFromPoints(vertices);

// Для Trimesh необходимо использовать индексные массивы треугольников
geometry.setIndex(triangleIndices);

Отладка столкновений с помощью визуализации

Визуализация AABB полезна для выявления проблем с коллизиями, таких как:

  • Несовпадение размеров тела и формы.
  • Ошибки при добавлении нескольких форм к одному телу.
  • Неожиданная динамика при вращении или смещении центра масс.

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

body.updateAABB();
wireframe.position.se t(
    (body.aabb.lowerBound.x + body.aabb.upperBound.x)/2,
    (body.aabb.lowerBound.y + body.aabb.upperBound.y)/2,
    (body.aabb.lowerBound.z + body.aabb.upperBound.z)/2
);
wireframe.scale.se t(
    body.aabb.upperBound.x - body.aabb.lowerBound.x,
    body.aabb.upperBound.y - body.aabb.lowerBound.y,
    body.aabb.upperBound.z - body.aabb.lowerBound.z
);

Такой подход позволяет наблюдать реальное положение и ориентацию тел, а также отследить возможные ошибки синхронизации с визуальными объектами.


Практические советы

  • Всегда вызывать updateAABB() перед визуализацией AABB, иначе данные будут устаревшими.
  • Для динамических тел лучше использовать линии или прозрачные каркасы, чтобы не мешать основной сцене.
  • Совмещение Cannon.js и three.js требует синхронизации position и quaternion объектов.
  • Для сложных форм, особенно Trimesh, полезно предварительно тестировать геометрию с малым количеством вершин, чтобы ускорить отладку.
  • Можно создать универсальный вспомогательный метод, который автоматически строит wireframe для любого тела, используя его формы и AABB.

Эта методика визуализации позволяет не только отлаживать физические симуляции, но и создавать наглядные инструменты для интерактивного обучения и демонстрации работы физического движка Cannon.js.