btConvexTriangleMeshShape: выпуклая сетка для динамики

btConvexTriangleMeshShape представляет собой одну из специализированных форм столкновений в физическом движке Ammo.js, основанного на Bullet Physics. Она используется для создания выпуклых треугольных сеток, позволяющих симулировать объекты сложной геометрии с корректным физическим взаимодействием, сохраняя при этом производительность. Основное отличие от других форм заключается в том, что она принимает произвольные треугольники, но автоматически преобразует их в выпуклую оболочку.


Основные характеристики

  • Выпуклость: Все вершины сетки автоматически приводятся к выпуклой оболочке, что обеспечивает корректное столкновение без проваливания внутрь объекта.
  • Статическая и динамическая поддержка: Форму можно использовать как для статических, так и для динамических тел, но производительность динамических тел лучше с btConvexHullShape, если количество вершин велико.
  • Производительность: Использует алгоритмы построения выпуклой оболочки, что делает расчёт коллизий относительно быстрым для умеренного числа треугольников.
  • Поддержка масштабирования: Объект можно масштабировать через метод setLocalScaling, что автоматически корректирует столкновения.

Создание объекта btConvexTriangleMeshShape

Для создания требуется объект btTriangleMesh, который хранит вершины и индексы треугольников. Последовательность действий:

// Создание треугольной сетки
let triangleMesh = new Ammo.btTriangleMesh();

// Добавление треугольников
triangleMesh.addTriangle(
    new Ammo.btVector3(0, 0, 0),
    new Ammo.btVector3(1, 0, 0),
    new Ammo.btVector3(0, 1, 0),
    true
);

// Создание выпуклой формы на основе сетки
let convexShape = new Ammo.btConvexTriangleMeshShape(triangleMesh, true);

Параметры конструктора:

  1. meshInterface – объект типа btStridingMeshInterface, чаще всего btTriangleMesh.
  2. calculateAabb (boolean) – если true, автоматически пересчитывается ограничивающий параллелепипед (AABB) для коллизий.

Методы и свойства

btConvexTriangleMeshShape наследует большинство методов базового класса btConvexShape, включая:

  • getBoundingSphere(center, radius) – получение центра и радиуса огибающей сферы.
  • recalcLocalAabb() – пересчёт локального AABB после изменения формы или масштаба.
  • setLocalScaling(scalingVector) – масштабирование формы.
  • getLocalScaling() – получение текущего масштаба.
  • calculateLocalInertia(mass, inertia) – вычисление инерции для динамических тел.

Пример вычисления инерции:

let mass = 10;
let localInertia = new Ammo.btVector3(0, 0, 0);
convexShape.calculateLocalInertia(mass, localInertia);

Масштабирование и трансформации

Масштабирование через setLocalScaling применяется к каждой вершине сетки при расчёте столкновений:

convexShape.setLocalScaling(new Ammo.btVector3(2, 1, 1.5));

После масштабирования важно вызвать recalcLocalAabb, чтобы физический движок корректно обновил границы объекта:

convexShape.recalcLocalAabb();

Интеграция с rigid body

Для использования формы в симуляции необходимо создать btRigidBody:

let transform = new Ammo.btTransform();
transform.setIdentity();
transform.setOrigin(new Ammo.btVector3(0, 10, 0));

let motionState = new Ammo.btDefaultMotionState(transform);
let mass = 5;
let localInertia = new Ammo.btVector3(0, 0, 0);

convexShape.calculateLocalInertia(mass, localInertia);

let rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, convexShape, localInertia);
let rigidBody = new Ammo.btRigidBody(rbInfo);

// Добавление тела в физический мир
physicsWorld.addRigidBody(rigidBody);

Особенности:

  • Для статических объектов масса должна быть равна 0.
  • Для динамических тел инерция вычисляется через calculateLocalInertia.
  • motionState обеспечивает синхронизацию между визуализацией и физическим движком.

Ограничения и рекомендации

  • Форма btConvexTriangleMeshShape подходит только для выпуклых объектов. Вогнутые сетки нужно разбивать на несколько выпуклых частей или использовать btBvhTriangleMeshShape для статических объектов.
  • Для объектов с большим количеством вершин динамика может снижаться. В таких случаях предпочтительно использовать btConvexHullShape, который напрямую строит выпуклую оболочку из массива вершин.
  • Проверка корректности вершин важна: коллизии могут некорректно работать, если вершины находятся в одной плоскости или почти совпадают.

Советы по оптимизации

  1. Минимизировать количество треугольников в исходной сетке.
  2. Использовать масштабирование на уровне btConvexShape, а не через модификацию вершин напрямую.
  3. Для динамических тел предпочитать простые геометрические формы (кубы, сферы, цилиндры) или объединение нескольких convex shapes через btCompoundShape.

Пример комбинирования нескольких форм

Для сложных объектов допустимо объединять несколько btConvexTriangleMeshShape в btCompoundShape:

let compound = new Ammo.btCompoundShape();
let offsetTransform = new Ammo.btTransform();
offsetTransform.setIdentity();
offsetTransform.setOrigin(new Ammo.btVector3(0, 0, 0));

compound.addChildShape(offsetTransform, convexShape);

Это позволяет создавать объекты с несколькими выпуклыми областями, сохраняя стабильность динамики.


Взаимодействие с другими формами

btConvexTriangleMeshShape корректно взаимодействует с другими convex shapes, включая:

  • btBoxShape
  • btSphereShape
  • btCapsuleShape
  • btConvexHullShape

Коллизии рассчитываются на основе алгоритма GJK (Gilbert–Johnson–Keerthi) для выпуклых тел, что обеспечивает точное и стабильное поведение в симуляции.


Особенности для Ammo.js

  • Конструктор и методы идентичны Bullet Physics, но с учетом особенностей памяти JavaScript и WebAssembly.
  • Важно освобождать объекты через Ammo.destroy() для предотвращения утечек памяти.
  • Для динамических сцен с частыми изменениями формы рекомендуется минимизировать создание новых объектов и использовать повторное выделение памяти.