Получение позиции и ориентации через MotionState

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

Основные принципы работы MotionState

Каждое тело (btRigidBody) может иметь собственный MotionState. Его основная задача — предоставление текущей трансформации тела (позиции и ориентации) и возможность её установки. MotionState используется движком для оптимизации: физический движок обновляет только трансформации, а визуальная часть читает их без дополнительных вычислений.

MotionState содержит два ключевых метода:

  • getWorldTransform(worldTrans) — получает текущую трансформацию тела.
  • setWorldTransform(worldTrans) — устанавливает трансформацию, обычно вызывается движком при изменении позиции объекта в физическом мире.

Фактически, MotionState — это интерфейс, через который происходит обмен информацией между движком и визуальной моделью.

Создание собственного MotionState

Для получения позиции и ориентации объектов можно использовать стандартный класс Ammo.btDefaultMotionState:

const startTransform = new Ammo.btTransform();
startTransform.setIdentity();
startTransform.setOrigin(new Ammo.btVector3(0, 10, 0)); // начальная позиция

const motionState = new Ammo.btDefaultMotionState(startTransform);
  • btTransform задаёт начальную трансформацию тела.
  • Метод setIdentity() сбрасывает трансформацию до стандартной (нулевая позиция, отсутствие вращения).
  • setOrigin() устанавливает начальное положение объекта.

Получение позиции через MotionState

Чтобы извлечь текущую позицию тела, необходимо:

  1. Получить MotionState у btRigidBody:
const bodyMotionState = rigidBody.getMotionState();
  1. Создать объект btTransform для хранения трансформации:
const trans = new Ammo.btTransform();
  1. Вызвать метод getWorldTransform:
bodyMotionState.getWorldTransform(trans);
  1. Извлечь позицию через getOrigin():
const origin = trans.getOrigin();
const x = origin.x();
const y = origin.y();
const z = origin.z();

Результатом являются координаты объекта в мировых единицах.

Получение ориентации (кватерниона) через MotionState

Для получения вращения используется getRotation() объекта btTransform:

const rotation = trans.getRotation();
const qx = rotation.x();
const qy = rotation.y();
const qz = rotation.z();
const qw = rotation.w();

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

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

После получения позиции и кватерниона можно синхронизировать физическое тело с графическим объектом:

mesh.position.set(x, y, z);
mesh.quaternion.set(qx, qy, qz, qw);

Такое обновление необходимо выполнять каждый кадр после шага симуляции physicsWorld.stepSimulation(deltaTime).

Особенности использования

  • Оптимизация: MotionState позволяет избежать постоянного чтения трансформации через btRigidBody.getCenterOfMassTransform(), что уменьшает нагрузку на движок.
  • Динамические объекты: MotionState актуален для тел с ненулевой массой. Статические тела можно обрабатывать напрямую через их трансформацию.
  • Копирование данных: Объект btTransform нужно создавать один раз и переиспользовать для каждого кадра, чтобы минимизировать выделение памяти и нагрузку сборщика мусора.
  • Обратная установка трансформации: При желании визуальный объект может изменять MotionState через setWorldTransform, но это следует делать аккуратно, чтобы не нарушить работу физики.

Пример полного цикла получения позиции и ориентации

function updateMeshFromPhysics(rigidBody, mesh) {
    const motionState = rigidBody.getMotionState();
    if (motionState) {
        const trans = new Ammo.btTransform();
        motionState.getWorldTransform(trans);

        const origin = trans.getOrigin();
        mesh.position.set(origin.x(), origin.y(), origin.z());

        const rotation = trans.getRotation();
        mesh.quaternion.set(rotation.x(), rotation.y(), rotation.z(), rotation.w());
    }
}

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

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

  • MotionState управляет трансформацией физического тела.
  • Использование getWorldTransform и setWorldTransform позволяет безопасно получать и задавать позицию и ориентацию.
  • Оптимизация работы с btTransform критична для производительности при больших сценах.
  • Кватернионы в Ammo.js соответствуют стандарту и могут напрямую использоваться для 3D визуализации.

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