btTransform: позиция и ориентация тела

В физическом движке Ammo.js btTransform представляет собой фундаментальный объект для работы с положением и ориентацией тел в трёхмерном пространстве. Он объединяет позицию (origin) и вращение (rotation) в единый контейнер, обеспечивая удобный способ управления положением объектов и их преобразованиями.

Структура btTransform

btTransform содержит два основных компонента:

  1. Позиция (origin) Представлена объектом типа btVector3. Хранит координаты тела в пространстве:

    let position = new Ammo.btVector3(x, y, z);

    Здесь x, y, z — координаты в мировых единицах. btVector3 поддерживает стандартные операции векторов: сложение, вычитание, масштабирование и нормализацию.

  2. Ориентация (rotation) Ориентация задаётся объектом btQuaternion, который хранит поворот через кватернион. Кватернионы позволяют избежать углов Эйлера и связанных с ними проблем gimbal lock.

    let rotation = new Ammo.btQuaternion(x, y, z, w);

    x, y, z, w — компоненты кватерниона. Основные операции с кватернионами: умножение, нормализация, преобразование в матрицу поворота.

Создание и инициализация btTransform

Для создания нового объекта btTransform используется конструктор без параметров или с параметрами позиции и вращения:

let transform = new Ammo.btTransform(); 
transform.setIdentity(); // инициализация как нейтральный трансформ
  • setIdentity() устанавливает трансформ в нулевое смещение и отсутствие вращения.
  • setOrigin(btVector3) задаёт позицию объекта.
  • setRotation(btQuaternion) задаёт ориентацию объекта.

Пример задания позиции и ориентации одновременно:

let transform = new Ammo.btTransform();
let origin = new Ammo.btVector3(0, 5, 0);
let rotation = new Ammo.btQuaternion(0, 0, 0, 1);

transform.setOrigin(origin);
transform.setRotation(rotation);

Получение данных из btTransform

Для получения текущих координат и ориентации используются методы:

  • getOrigin() — возвращает btVector3, содержащий позицию.
  • getRotation() — возвращает btQuaternion, содержащий ориентацию.
let pos = transform.getOrigin();
let rot = transform.getRotation();

console.log(pos.x(), pos.y(), pos.z());
console.log(rot.x(), rot.y(), rot.z(), rot.w());

Применение трансформаций к телам

btTransform используется в:

  1. Создании динамических и статических тел через btRigidBodyConstructionInfo.

  2. Обновлении позиции объекта в мире:

    body.setWorldTransform(transform);
  3. Считывании текущего состояния тела:

    let currentTransform = body.getWorldTransform();
    let currentPos = currentTransform.getOrigin();

Комбинирование трансформаций

Трансформации можно комбинировать с помощью кватернионного умножения и сложения векторов:

let t1 = new Ammo.btTransform();
let t2 = new Ammo.btTransform();
t1.setIdentity();
t2.setIdentity();

t1.setOrigin(new Ammo.btVector3(1, 2, 3));
t2.setRotation(new Ammo.btQuaternion(0, 0, 0.707, 0.707));

t1.op_mul(t2); // комбинирование трансформаций

Метод op_mul() выполняет композицию трансформаций, объединяя смещение и поворот. Это полезно для расчета позиции дочерних объектов относительно родителя.

Вращение через btTransform

Вращение объекта через btTransform обычно выполняется с использованием кватерниона. Прямое задание углов Эйлера требует преобразования в кватернион:

function eulerToQuaternion(yaw, pitch, roll) {
    let cy = Math.cos(yaw * 0.5);
    let sy = Math.sin(yaw * 0.5);
    let cp = Math.cos(pitch * 0.5);
    let sp = Math.sin(pitch * 0.5);
    let cr = Math.cos(roll * 0.5);
    let sr = Math.sin(roll * 0.5);

    let q = new Ammo.btQuaternion(
        sr * cp * cy - cr * sp * sy,
        cr * sp * cy + sr * cp * sy,
        cr * cp * sy - sr * sp * cy,
        cr * cp * cy + sr * sp * sy
    );
    return q;
}

let rotation = eulerToQuaternion(0, Math.PI / 2, 0);
transform.setRotation(rotation);

Преобразование btTransform в матрицу

Для интеграции с графикой или WebGL трансформ можно преобразовать в 4×4 матрицу:

let matrix = new Ammo.btMatrix3x3();
transform.getBasis(matrix);
let origin = transform.getOrigin();

Базис (basis) — это матрица 3×3, представляющая поворот. Совмещая её с позицией, можно получить полную матрицу модели.

Практические рекомендации

  • Всегда использовать setIdentity() при создании новых трансформов для предотвращения неопределённого состояния.

  • Для последовательного применения нескольких поворотов предпочтительно использовать кватернионы вместо углов Эйлера.

  • Для анимации тел можно интерполировать кватернионы с помощью SLERP, сохраняя плавность вращения.

  • Освобождение памяти объектов Ammo.js важно, т.к. библиотека управляет памятью вручную:

    Ammo.destroy(transform);
    Ammo.destroy(origin);
    Ammo.destroy(rotation);

Связь btTransform с физическим миром

В контексте btDiscreteDynamicsWorld btTransform определяет:

  • Начальное положение тел при создании btRigidBody.
  • Текущую позицию и ориентацию тел для симуляции коллизий.
  • Цели для кинематических тел через setWorldTransform() без влияния силы.

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