Ammo.js — это порт библиотеки Bullet Physics на JavaScript с использованием WebAssembly. Она позволяет создавать физически реалистичные симуляции, включая динамику тел, столкновения и реакцию на силы. Основной единицей симуляции является rigid body — жёсткое тело, обладающее массой, инерцией и формой столкновения.
Для создания тела требуется:
btCollisionShape)
— описывает границы объекта для системы столкновений.btRigidBody) — соединяет форму и
массу в полноценный физический объект.Пример базового создания тела:
let shape = new Ammo.btBoxShape(new Ammo.btVector3(1, 1, 1));
let mass = 1;
let localInertia = new Ammo.btVector3(0, 0, 0);
shape.calculateLocalInertia(mass, localInertia);
let transform = new Ammo.btTransform();
transform.setIdentity();
transform.setOrigin(new Ammo.btVector3(0, 5, 0));
let motionState = new Ammo.btDefaultMotionState(transform);
let rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, shape, localInertia);
let body = new Ammo.btRigidBody(rbInfo);
physicsWorld.addRigidBody(body);
В стандартных примерах Ammo.js формы часто создаются заранее. Для процедурной генерации требуется создавать формы во время выполнения на основе данных, доступных только во время исполнения программы.
Ammo.js поддерживает несколько основных форм:
btBoxShape,
btSphereShape, btCapsuleShape,
btCylinderShape.compound) формы:
btCompoundShape позволяет объединять несколько простых форм
в один объект.btBvhTriangleMeshShape): используются для
статических сложных объектов.btConvexHullShape):
создаётся на основе набора вершин, полезна для динамических сложных
тел.Для процедурной генерации чаще всего применяются Convex Hull и Compound Shape, поскольку они позволяют строить форму на лету.
btConvexHullShape принимает набор вершин и формирует
минимальный выпуклый объём, который будет использоваться для
столкновений:
let hullShape = new Ammo.btConvexHullShape();
vertices.forEach(v => {
hullShape.addPoint(new Ammo.btVector3(v.x, v.y, v.z));
});
hullShape.optimizeConvexHull();
vertices — массив объектов с координатами
{x, y, z}.optimizeConvexHull уменьшает количество вершин,
ускоряя расчёты столкновений.После создания формы можно использовать стандартную схему с массой и инерцией для добавления тела в мир.
btCompoundShape позволяет объединять несколько форм с
собственными трансформациями:
let compound = new Ammo.btCompoundShape();
let boxShape = new Ammo.btBoxShape(new Ammo.btVector3(1, 1, 1));
let sphereShape = new Ammo.btSphereShape(0.5);
let boxTransform = new Ammo.btTransform();
boxTransform.setIdentity();
boxTransform.setOrigin(new Ammo.btVector3(0, 1, 0));
let sphereTransform = new Ammo.btTransform();
sphereTransform.setIdentity();
sphereTransform.setOrigin(new Ammo.btVector3(2, 0, 0));
compound.addChildShape(boxTransform, boxShape);
compound.addChildShape(sphereTransform, sphereShape);
Compound Shape особенно полезна, когда нужно создавать динамические объекты из нескольких примитивов, например, процедурные роботы или строительные блоки.
Для статических объектов с высокой детализацией используется
btBvhTriangleMeshShape. Процедурная генерация треугольной
сетки может выполняться на основе:
Пример создания меша:
let triangleMesh = new Ammo.btTriangleMesh();
for (let i = 0; i < faces.length; i++) {
let f = faces[i];
triangleMesh.addTriangle(
new Ammo.btVector3(f.a.x, f.a.y, f.a.z),
new Ammo.btVector3(f.b.x, f.b.y, f.b.z),
new Ammo.btVector3(f.c.x, f.c.y, f.c.z),
true
);
}
let meshShape = new Ammo.btBvhTriangleMeshShape(triangleMesh, true, true);
faces — массив треугольников с вершинами
{a, b, c}.Для процедурной генерации важно уметь обновлять форму
объекта после создания. Прямой замены формы в
btRigidBody нет, поэтому используются следующие
подходы:
btCompoundShape с несколькими дочерними
формами, где можно добавлять/удалять дочерние элементы динамически.physicsWorld.removeRigidBody(body);
Ammo.destroy(body);
body = new Ammo.btRigidBody(new Ammo.btRigidBodyConstructionInfo(mass, motionState, newShape, localInertia));
physicsWorld.addRigidBody(body);
btConvexHullShape и btBvhTriangleMeshShape
должны быть оптимизированы, иначе столкновения будут медленными.Такой подход обеспечивает гибкость и возможность создавать уникальные физические объекты без предварительной подготовки, полностью управляя их свойствами и формой столкновений на лету.