btMotionState является ключевым интерфейсом в физическом
движке Bullet, реализованном в JavaScript через Ammo.js. Он предназначен
для синхронизации состояния физического тела с внешним представлением
объекта в сцене, например, в WebGL или Three.js. В отличие от прямого
обновления трансформаций через btRigidBody,
btMotionState позволяет отделить физические расчёты от
визуального представления, обеспечивая чистую архитектуру и предотвращая
прямое вмешательство в симуляцию.
Интерфейс btMotionState имеет два ключевых метода:
getWorldTransform(transform) Этот
метод вызывается движком при создании тела или при необходимости узнать
текущую позицию и ориентацию объекта. Он должен записать трансформацию в
переданный объект transform. Пример реализации:class MyMotionState extends Ammo.btMotionState {
constructor(mesh) {
super();
this.mesh = mesh;
this.transform = new Ammo.btTransform();
}
getWorldTransform(worldTrans) {
const pos = this.mesh.position;
const quat = this.mesh.quaternion;
this.transform.setOrigin(new Ammo.btVector3(pos.x, pos.y, pos.z));
this.transform.setRotation(new Ammo.btQuaternion(quat.x, quat.y, quat.z, quat.w));
worldTrans.setOrigin(this.transform.getOrigin());
worldTrans.setRotation(this.transform.getRotation());
}
setWorldTransform(worldTrans) {
const origin = worldTrans.getOrigin();
const rotation = worldTrans.getRotation();
this.mesh.position.set(origin.x(), origin.y(), origin.z());
this.mesh.quaternion.set(rotation.x(), rotation.y(), rotation.z(), rotation.w());
}
}
setWorldTransform(transform) Метод
вызывается движком после каждого шага симуляции, чтобы обновить
визуальное представление объекта. Он передаёт вычисленные физические
координаты, которые затем применяются к связанной модели.При создании тела в Ammo.js важно передать экземпляр
btMotionState в конструктор btRigidBody:
const motionState = new MyMotionState(mesh);
const rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, shape, localInertia);
const body = new Ammo.btRigidBody(rbInfo);
physicsWorld.addRigidBody(body);
Использование btMotionState обеспечивает корректное
обновление визуального объекта независимо от внутренней симуляции. Это
особенно важно при высокой частоте обновления физики и сложных
сценах.
getWorldTransform и
setWorldTransform.btDefaultMotionState, но при необходимости кастомной
синхронизации лучше создавать собственный класс.btTransform и
btVector3 внутри MotionState, чтобы уменьшить
нагрузку на сборщик мусора.В связке Ammo.js и Three.js btMotionState чаще всего
используется для передачи данных между btRigidBody и
THREE.Mesh. Важно учитывать:
Ammo.destroy() после завершения работы,
иначе возникает утечка памяти.btMotionState позволяет реализовать:
setWorldTransform для
локальных объектов.getWorldTransform и setWorldTransform можно
применять фильтры, ограничения или модификации движений объекта.Использование btMotionState является стандартным
подходом в Ammo.js для обеспечения стабильной и гибкой связи между
физической симуляцией и визуальными объектами. Этот интерфейс
обеспечивает чистую архитектуру и позволяет строить сложные симуляции с
минимальными проблемами синхронизации.