Создание динамических тел

Динамическое тело в Ammo.js представляет собой объект, который подчиняется законам физики: под действием сил оно может двигаться, вращаться и сталкиваться с другими объектами. Для создания динамического тела необходимы три основных компонента: форма (collision shape), масса (mass) и тело (rigid body).

const shape = new Ammo.btBoxShape(new Ammo.btVector3(1, 1, 1));
const mass = 1;
const transform = new Ammo.btTransform();
transform.setIdentity();
transform.setOrigin(new Ammo.btVector3(0, 10, 0));

const motionState = new Ammo.btDefaultMotionState(transform);
const localInertia = new Ammo.btVector3(0, 0, 0);
shape.calculateLocalInertia(mass, localInertia);

const rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, shape, localInertia);
const body = new Ammo.btRigidBody(rbInfo);
physicsWorld.addRigidBody(body);

Ключевые моменты:

  • Collision Shape — определяет форму тела: коробка, сфера, цилиндр, конус или сложные триангулярные меши.
  • Mass — масса тела; масса = 0 создаёт статическое тело.
  • Local Inertia — влияет на вращение объекта; для динамических тел обязательно вычислять с помощью calculateLocalInertia.
  • Motion State — хранит текущую трансформацию тела и синхронизирует её с визуальной частью.

Типы форм тел

Ammo.js поддерживает следующие основные формы:

  1. btBoxShape — прямоугольный параллелепипед.
  2. btSphereShape — сфера.
  3. btCylinderShape — цилиндр.
  4. btConeShape — конус.
  5. btCapsuleShape — капсула (используется часто для персонажей).
  6. btConvexHullShape — выпуклая оболочка, создаваемая из множества точек.
  7. btBvhTriangleMeshShape — сложный статический меш для неровных поверхностей.

Выбор формы влияет на точность столкновений и производительность. Простые формы (box, sphere) быстрее и стабильнее при симуляции.


Настройка физики тела

Динамическое тело можно настраивать с помощью свойств:

  • setFriction(value) — коэффициент трения при контакте.
  • setRestitution(value) — коэффициент упругости (отражение при столкновении).
  • setDamping(linear, angular) — демпфирование линейного и углового движения.
  • setActivationState(state) — управление режимами сна для оптимизации.

Пример:

body.setFriction(0.5);
body.setRestitution(0.7);
body.setDamping(0.1, 0.1);
body.setActivationState(4); // DISABLE_DEACTIVATION

Применение сил и импульсов

Ammo.js позволяет динамически воздействовать на тело через силы, импульсы и моменты.

  • Сила (force) — длительное воздействие, учитывающее массу:
body.applyCentralForce(new Ammo.btVector3(0, 100, 0));
  • Импульс (impulse) — мгновенное изменение скорости:
body.applyCentralImpulse(new Ammo.btVector3(0, 10, 0));
  • Torque — вращательный момент:
body.applyTorque(new Ammo.btVector3(0, 5, 0));
  • Impulse at point — сила, приложенная к конкретной точке, создаёт вращение:
const relPos = new Ammo.btVector3(1, 0, 0);
body.applyImpulse(new Ammo.btVector3(0, 10, 0), relPos);

Эти методы позволяют создавать реалистичные реакции на столкновения и движения объектов.


Связь визуальных объектов с телами

В графических движках необходимо синхронизировать позицию и ориентацию визуального объекта с динамическим телом. Ammo.js хранит данные в btTransform:

const ms = body.getMotionState();
if (ms) {
    const transform = new Ammo.btTransform();
    ms.getWorldTransform(transform);
    const origin = transform.getOrigin();
    const rotation = transform.getRotation();
    mesh.position.set(origin.x(), origin.y(), origin.z());
    mesh.quaternion.set(rotation.x(), rotation.y(), rotation.z(), rotation.w());
}

Важно регулярно обновлять визуальный объект после каждого шага симуляции.


Управление сном (Sleeping) и производительность

Динамические тела могут переходить в режим сна для оптимизации:

  • Активное тело — движется и участвует в расчетах столкновений.
  • Спящее тело — неподвижно, расчеты игнорируются, пока не будет воздействий.
body.forceActivationState(Ammo.DISABLE_DEACTIVATION); // тело всегда активно
body.activate(); // пробуждение спящего тела

Эффективное использование механизма сна позволяет поддерживать высокую производительность в больших сценах с сотнями тел.


Взаимодействие тел и мир

Динамическое тело может взаимодействовать с другими телами, статическими объектами и триггерными зонами. Ammo.js поддерживает детектирование столкновений через contact manifolds:

const dispatcher = physicsWorld.getDispatcher();
const numManifolds = dispatcher.getNumManifolds();
for (let i = 0; i < numManifolds; i++) {
    const manifold = dispatcher.getManifoldByIndexInternal(i);
    const body0 = manifold.getBody0();
    const body1 = manifold.getBody1();
    const numContacts = manifold.getNumContacts();
    for (let j = 0; j < numContacts; j++) {
        const pt = manifold.getContactPoint(j);
        if (pt.getDistance() < 0) {
            // Обработка столкновения
        }
    }
}

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


Практические советы

  • Для мелких объектов лучше использовать простые формы (btBoxShape, btSphereShape) — это экономит ресурсы.
  • Для больших и сложных объектов использовать btConvexHullShape или btBvhTriangleMeshShape.
  • Всегда учитывать массу и инерцию, чтобы симуляция выглядела реалистично.
  • Частота обновления мира (stepSimulation) напрямую влияет на точность движения и столкновений.

Эти принципы позволяют создавать полноценные динамические объекты в Ammo.js, обеспечивая реалистичное взаимодействие с физическим миром и высокой производительностью.