Ammo.js — это JavaScript-порт популярной библиотеки Bullet Physics,
обеспечивающий высокоэффективное моделирование физики в браузере.
Основной объект работы — физический мир
(btDiscreteDynamicsWorld), в котором создаются тела, на
которые действуют силы, столкновения и ограничения. Для имитации
гравитации отдельного тела важны следующие компоненты:
btRigidBody) — объект с
массой, формой и физическими свойствами.btCollisionShape) —
геометрия объекта, определяющая взаимодействие с другими телами.Для работы с гравитацией необходимо создать физический мир:
const collisionConfiguration = new Ammo.btDefaultCollisionConfiguration();
const dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration);
const broadphase = new Ammo.btDbvtBroadphase();
const solver = new Ammo.btSequentialImpulseConstraintSolver();
const dynamicsWorld = new Ammo.btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);
// Установка глобальной гравитации
dynamicsWorld.setGravity(new Ammo.btVector3(0, -9.81, 0));
Здесь btVector3 задает вектор гравитации. Для
большинства симуляций по оси Y направлено вниз.
Форма тела влияет на столкновения:
const boxShape = new Ammo.btBoxShape(new Ammo.btVector3(1, 1, 1)); // куб со стороной 2
Для более сложных объектов можно использовать
btSphereShape, btCylinderShape или
btConvexHullShape.
Масса определяет подверженность гравитации:
const mass = 5; // кг
const localInertia = new Ammo.btVector3(0, 0, 0);
boxShape.calculateLocalInertia(mass, localInertia);
Если масса равна нулю, тело становится статическим и на него не действует гравитация.
const startTransform = new Ammo.btTransform();
startTransform.setIdentity();
startTransform.setOrigin(new Ammo.btVector3(0, 10, 0)); // начальная позиция
const motionState = new Ammo.btDefaultMotionState(startTransform);
const rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, boxShape, localInertia);
const rigidBody = new Ammo.btRigidBody(rbInfo);
// Добавление тела в мир
dynamicsWorld.addRigidBody(rigidBody);
Ammo.js позволяет применять силу на отдельное тело независимо от глобальной гравитации:
const customGravity = new Ammo.btVector3(0, -15, 0); // сильнее стандартной
rigidBody.setGravity(customGravity);
Если нужно временно отключить гравитацию для конкретного объекта:
rigidBody.setGravity(new Ammo.btVector3(0, 0, 0));
Для моделирования нестандартных сценариев можно использовать метод
applyCentralForce или applyCentralImpulse:
const force = new Ammo.btVector3(0, 50, 0); // подъемная сила
rigidBody.applyCentralForce(force);
const impulse = new Ammo.btVector3(10, 0, 0); // мгновенный толчок
rigidBody.applyCentralImpulse(impulse);
Метод applyCentralForce действует каждую итерацию
симуляции, а applyCentralImpulse — разово.
Каждый кадр необходимо обновлять физический мир и синхронизировать визуальные объекты:
const deltaTime = 1 / 60; // 60 FPS
dynamicsWorld.stepSimulation(deltaTime, 10);
const transform = new Ammo.btTransform();
rigidBody.getMotionState().getWorldTransform(transform);
const origin = transform.getOrigin();
const rotation = transform.getRotation();
// Применение к визуальному объекту (например, Three.js)
mesh.position.set(origin.x(), origin.y(), origin.z());
mesh.quaternion.set(rotation.x(), rotation.y(), rotation.z(), rotation.w());
stepSimulation учитывает все силы, включая
индивидуальные гравитации и столкновения.
deltaTime
повышает точность, но увеличивает нагрузку на CPU.fixed timestep) и ограничивать максимальное количество
итераций.Ammo.js поддерживает compound shapes, позволяющие комбинировать несколько форм в одном теле. Каждая часть может иметь свой центр масс, что важно для правильного расчета гравитации и вращения.
const compound = new Ammo.btCompoundShape();
const boxTransform = new Ammo.btTransform();
boxTransform.setIdentity();
boxTransform.setOrigin(new Ammo.btVector3(0, 1, 0));
compound.addChildShape(boxTransform, boxShape);
const sphereShape = new Ammo.btSphereShape(1);
const sphereTransform = new Ammo.btTransform();
sphereTransform.setIdentity();
sphereTransform.setOrigin(new Ammo.btVector3(0, -1, 0));
compound.addChildShape(sphereTransform, sphereShape);
После этого создается btRigidBody с компаундной формой,
и на него можно задавать индивидуальную гравитацию, точно так же как на
простые тела.
Эта методика позволяет создавать точные симуляции отдельных объектов, управлять их гравитацией независимо от мира, добавлять силы и импульсы, а также интегрировать физику с визуализацией, обеспечивая реалистичное поведение тел в трехмерном пространстве.