Работа с физическим движком Ammo.js требует понимания двух основных систем координат: визуальной (например, Three.js) и физической (Bullet Physics, на котором основан Ammo.js). Визуальные объекты и физические тела используют разные представления позиции и ориентации, поэтому точное преобразование между ними критично для корректной симуляции.
В Ammo.js позиции и скорости объектов задаются через
класс btVector3, а ориентация — через
btQuaternion. Эти классы предоставляют методы для чтения и
записи координат:
let position = new Ammo.btVector3(0, 10, 0);
let rotation = new Ammo.btQuaternion(0, 0, 0, 1);
Визуальные движки часто используют объекты вроде
THREE.Vector3 и THREE.Quaternion, что требует
конвертации при синхронизации.
Позиция объекта в визуальном пространстве обычно напрямую передается в физический движок с преобразованием единиц, если они различаются. Например:
function threeVectorToAmmo(v) {
return new Ammo.btVector3(v.x, v.y, v.z);
}
function ammoVectorToThree(v) {
return new THREE.Vector3(v.x(), v.y(), v.z());
}
Особенность Ammo.js: методы x(),
y(), z() возвращают значения, но для изменения
координат необходимо использовать setValue(x, y, z).
let physPos = new Ammo.btVector3();
physPos.setValue(1, 2, 3);
Кватернионы в Ammo.js и Three.js имеют одинаковую структуру (x, y, z, w), но важно учитывать порядок умножения и направление осей при наложении вращений:
function threeQuatToAmmo(q) {
return new Ammo.btQuaternion(q.x, q.y, q.z, q.w);
}
function ammoQuatToThree(q) {
return new THREE.Quaternion(q.x(), q.y(), q.z(), q.w());
}
Для корректной синхронизации объекта визуального движка с физикой нужно учитывать, что вращения Ammo.js могут быть обновлены после шага симуляции:
let transform = body.getWorldTransform();
let origin = transform.getOrigin();
let rotation = transform.getRotation();
mesh.position.set(origin.x(), origin.y(), origin.z());
mesh.quaternion.set(rotation.x(), rotation.y(), rotation.z(), rotation.w());
Ammo.js предоставляет объект btTransform, который хранит одновременно позицию и ориентацию. Из него можно извлекать матрицу для визуализации:
let transform = new Ammo.btTransform();
body.getMotionState().getWorldTransform(transform);
let origin = transform.getOrigin();
let rotation = transform.getRotation();
let matrix = new THREE.Matrix4();
matrix.compose(
new THREE.Vector3(origin.x(), origin.y(), origin.z()),
new THREE.Quaternion(rotation.x(), rotation.y(), rotation.z(), rotation.w()),
new THREE.Vector3(1, 1, 1)
);
mesh.matrix = matrix;
mesh.matrixAutoUpdate = false;
Ключевой момент: btTransform всегда
хранит мировые координаты тела относительно сцены физического
движка.
При работе с Ammo.js часто требуется:
let t = new Ammo.btTransform();
t.setIdentity();
t.setOrigin(threeVectorToAmmo(mesh.position));
t.setRotation(threeQuatToAmmo(mesh.quaternion));
body.setWorldTransform(t);
body.getMotionState().getWorldTransform(t);
mesh.position.copy(ammoVectorToThree(t.getOrigin()));
mesh.quaternion.copy(ammoQuatToThree(t.getRotation()));
Использование setIdentity() важно, чтобы избежать
накопления ошибок при последовательных преобразованиях.
Ammo.js различает локальные координаты тела и
мировые координаты сцены. Методы getWorldTransform() и
setWorldTransform() оперируют именно мировыми координатами.
Для преобразования локальных координат относительно родительских тел
можно использовать:
let localTransform = new Ammo.btTransform();
body.getMotionState().getWorldTransform(localTransform);
let parentTransform = parentBody.getWorldTransform();
localTransform.op_sub(parentTransform);
Прямое использование локальных координат без преобразования может привести к некорректному поведению при сложных иерархиях тел.
Для правильной анимации объектов и обработки столкновений:
physicsWorld.stepSimulation(deltaTime, 10);
bodies.forEach((body, i) => {
let mesh = meshes[i];
let t = new Ammo.btTransform();
body.getMotionState().getWorldTransform(t);
mesh.position.copy(ammoVectorToThree(t.getOrigin()));
mesh.quaternion.copy(ammoQuatToThree(t.getRotation()));
});
btVector3 и
btQuaternion каждый кадр — лучше использовать
переиспользуемые экземпляры.btTransform для групповых обновлений
позиции и вращения.q_new = q_delta * q_current направление вращения зависит от
порядка.Эти правила и методы позволяют синхронизировать визуальные объекты с физикой, управлять положением и ориентацией тел, а также корректно обрабатывать взаимодействия между объектами в трехмерной среде с использованием Ammo.js.