Библиотека Ammo.js предоставляет мощный инструментарий для работы с физикой в 3D-пространстве, и одним из ключевых элементов для сложных коллизий является класс btCompoundShape. Этот класс позволяет создавать составные коллизионные формы, объединяя несколько простых примитивов, таких как коробки, сферы или цилиндры, в единую физическую сущность.
btCompoundShape наследует функциональность базового
интерфейса коллизионных объектов. Он не хранит напрямую геометрию
каждого примитива, а поддерживает массив вложенных форм с локальными
трансформациями. Каждая вложенная форма (child shape) имеет
собственное смещение и ориентацию относительно центра масс составной
формы. Это позволяет моделировать сложные объекты, например машины,
роботов или мебели, с высокой точностью коллизий.
Ключевые моменты:
btTransform, задающий её позицию и вращение внутри
составной формы.Создание составной формы начинается с инициализации объекта btCompoundShape:
let compoundShape = new Ammo.btCompoundShape();
Для добавления примитива создаётся соответствующая форма, например, btBoxShape:
let boxShape = new Ammo.btBoxShape(new Ammo.btVector3(1, 1, 1));
Далее формируется локальная трансформация:
let transform = new Ammo.btTransform();
transform.setIdentity();
transform.setOrigin(new Ammo.btVector3(0, 2, 0));
И добавляется к составной форме:
compoundShape.addChildShape(transform, boxShape);
Каждое добавление автоматически учитывается при расчёте инерции и коллизий, однако для динамических тел рекомендуется вызвать метод обновления локального центра масс:
compoundShape.calculatePrincipalAxisTransform(new Ammo.btTransform(), new Ammo.btVector3());
btCompoundShape предоставляет несколько методов для работы с дочерними объектами:
getNumChildShapes() — возвращает количество
примитивов.getChildShape(index) — возвращает форму по
индексу.getChildTransform(index) — возвращает локальную
трансформацию конкретного примитива.updateChildTransform(index, newTransform, shouldRecalculateLocalAabb)
— позволяет изменить трансформацию примитива после добавления. Параметр
shouldRecalculateLocalAabb отвечает за пересчёт локального
AABB (Axis-Aligned Bounding Box) для корректного расчёта
столкновений.Пример изменения позиции примитива:
let newTransform = new Ammo.btTransform();
newTransform.setIdentity();
newTransform.setOrigin(new Ammo.btVector3(0, 3, 0));
compoundShape.updateChildTransform(0, newTransform, true);
Составные формы чаще всего применяются вместе с btRigidBody для динамических объектов:
let mass = 10;
let localInertia = new Ammo.btVector3(0, 0, 0);
compoundShape.calculateLocalInertia(mass, localInertia);
let motionState = new Ammo.btDefaultMotionState();
let rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, compoundShape, localInertia);
let rigidBody = new Ammo.btRigidBody(rbInfo);
Важно учитывать, что расчёт инерции
(calculateLocalInertia) обязателен для динамических тел,
иначе объект будет вести себя как статический. Для статических объектов
с mass = 0 вызов не требуется.
calculatePrincipalAxisTransform.Использование btCompoundShape позволяет балансировать между точностью коллизий и производительностью, обеспечивая гибкость при моделировании объектов любой сложности в Ammo.js.