Ammo.js — это JavaScript-порт известной физической библиотеки Bullet Physics, обеспечивающей реалистичную симуляцию твердых тел, столкновений и физических ограничений. Одной из ключевых возможностей является использование ограничений (constraints) для соединения объектов с определенной степенью свободы и визуализация их поведения через оси и направляющие.
Ammo.js поддерживает несколько основных типов ограничений:
Point-to-Point Constraint (btPoint2PointConstraint) Обеспечивает соединение двух тел в одной точке, как шарнир.
Hinge Constraint (btHingeConstraint) Позволяет вращение одного тела относительно оси на другом, как дверная петля.
Slider Constraint (btSliderConstraint) Позволяет скользить вдоль одной оси и вращаться вокруг нее.
Cone Twist Constraint (btConeTwistConstraint) Ограничивает вращение в пределах конуса и позволяет поворот вокруг оси.
Generic 6 DOF Constraint (btGeneric6DofConstraint) Универсальное ограничение с управлением по шести степеням свободы.
Для отладки физической симуляции крайне важно видеть оси, точки соединения и диапазоны вращения. Визуализация обычно строится с помощью трех компонентов:
Точки соединения — маленькие сферы или крестики, показывающие координаты привязки.
Оси ограничений — линии, цвет которых соответствует типу движения:
Диапазоны движения — конусы или стрелки, показывающие пределы углов и скольжения.
Для генерации визуальных элементов используют либо нативные объекты WebGL/Three.js, либо вспомогательные библиотеки, создавая Mesh или Line с координатами из Ammo.js.
function createAxis(length = 1) {
const axes = new THREE.Group();
const materialX = new THREE.LineBasicMaterial({ color: 0xff0000 });
const geometryX = new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(0,0,0),
new THREE.Vector3(length,0,0)
]);
axes.add(new THREE.Line(geometryX, materialX));
const materialY = new THREE.LineBasicMaterial({ color: 0x00ff00 });
const geometryY = new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(0,0,0),
new THREE.Vector3(0,length,0)
]);
axes.add(new THREE.Line(geometryY, materialY));
const materialZ = new THREE.LineBasicMaterial({ color: 0x0000ff });
const geometryZ = new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(0,0,0),
new THREE.Vector3(0,0,length)
]);
axes.add(new THREE.Line(geometryZ, materialZ));
return axes;
}
const hinge = new Ammo.btHingeConstraint(bodyA, bodyB, pivotA, pivotB, axisA, axisB, true);
physicsWorld.addConstraint(hinge, true);
const axisHelper = createAxis(0.5);
scene.add(axisHelper);
// Обновление позиции осей в рендер-цикле
function updateAxis() {
const transform = new Ammo.btTransform();
hinge.getAFrame(transform);
const origin = transform.getOrigin();
const rotation = transform.getRotation();
axisHelper.position.set(origin.x(), origin.y(), origin.z());
axisHelper.quaternion.set(rotation.x(), rotation.y(), rotation.z(), rotation.w());
}
Для конусных или 6 DOF ограничений строят визуальные объекты, повторяющие углы и длины линейных степеней свободы:
const coneGeometry = new THREE.ConeGeometry(Math.tan(maxAngle) * radius, radius, 32);
const coneMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00, wireframe: true });
const coneMesh = new THREE.Mesh(coneGeometry, coneMaterial);
scene.add(coneMesh);
coneMesh.position.copy(axisHelper.position);
coneMesh.quaternion.copy(axisHelper.quaternion);
Ammo.js не хранит визуальные объекты внутри себя, поэтому синхронизация происходит вручную:
THREE.SphereGeometry(0.05).THREE.Line с яркими
цветами для каждой координаты.Ammo.js предоставляет точные данные о трансформациях ограничений. Основная задача визуализации — перевод этих данных в графические объекты Three.js или другой 3D-библиотеки. В результате создается наглядное представление работы ограничений, позволяющее отлаживать симуляцию, проверять физические модели и демонстрировать движение объектов в реальном времени.