Гравитация отдельного тела

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);

Если масса равна нулю, тело становится статическим и на него не действует гравитация.

Формирование rigid body

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 с компаундной формой, и на него можно задавать индивидуальную гравитацию, точно так же как на простые тела.


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