В физическом движке Ammo.js, основанном на Bullet Physics, обработка столкновений и получение информации о точках пересечения требует работы с collision objects, rigid bodies и manifold points. Для точного определения нормалей и координат столкновений используется система manifold callbacks, которая позволяет получать детальные сведения о контактах между объектами.
Каждое столкновение между двумя rigid body представлено через btPersistentManifold, который содержит список btManifoldPoint. Основные свойства btManifoldPoint:
getPositionWorldOnA() — возвращает координату точки
контакта на объекте A в мировых координатах.getPositionWorldOnB() — координата на объекте B.getNormalWorldOnB() — вектор нормали на объекте B.getDistance() — расстояние между точками контакта;
отрицательное значение указывает на проникновение.Для получения всех контактов в сцене используется dispatcher, который управляет списком всех столкновений:
let dispatcher = physicsWorld.getDispatcher();
let numManifolds = dispatcher.getNumManifolds();
for (let i = 0; i < numManifolds; i++) {
let manifold = dispatcher.getManifoldByIndexInternal(i);
let numContacts = manifold.getNumContacts();
for (let j = 0; j < numContacts; j++) {
let contactPoint = manifold.getContactPoint(j);
let posA = contactPoint.getPositionWorldOnA();
let posB = contactPoint.getPositionWorldOnB();
let normalB = contactPoint.getNormalWorldOnB();
}
}
Ключевой момент: нормаль всегда направлена от объекта B к объекту A, что важно учитывать при расчётах отражения или силы столкновения.
Для вычисления фактической точки пересечения между двумя объектами можно использовать среднее значение точек на объектах A и B:
let intersectionPos = new Ammo.btVector3(
(posA.x() + posB.x()) / 2,
(posA.y() + posB.y()) / 2,
(posA.z() + posB.z()) / 2
);
Это даёт наиболее точное приближение реальной точки контакта, особенно при работе с сложными формами.
Для обнаружения пересечений с помощью лучей
используется rayTest или rayTestSingle:
let rayFrom = new Ammo.btVector3(0, 10, 0);
let rayTo = new Ammo.btVector3(0, 0, 0);
let rayCallback = new Ammo.ClosestRayResultCallback(rayFrom, rayTo);
physicsWorld.rayTest(rayFrom, rayTo, rayCallback);
if (rayCallback.hasHit()) {
let hitPoint = rayCallback.get_hitPointWorld();
let hitNormal = rayCallback.get_hitNormalWorld();
}
Особенности:
get_hitPointWorld() возвращает мировую координату
пересечения луча с объектом.get_hitNormalWorld() — нормаль поверхности в точке
попадания.Объекты типа btVector3 требуют ручного извлечения
координат для работы в стандартных структурах Jav * aScript:
function vec3ToObj(btVec) {
return { x: btVec.x(), y: btVec.y(), z: btVec.z() };
}
let intersection = vec3ToObj(intersectionPos);
let normal = vec3ToObj(normalB);
Это упрощает интеграцию с рендерингом и системой визуализации.
Ammo.js позволяет фильтровать столкновения с помощью масок коллизий:
group — категория объекта.mask — определяет, с какими группами может
взаимодействовать объект.Применение масок предотвращает обработку ненужных пересечений, повышая производительность, особенно при большом количестве объектов.
btVector3 и btManifoldPoint
после использования, чтобы избежать утечек памяти:Ammo.destroy(intersectionPos);
let normalVec = new Ammo.btVector3(normalB.x(), normalB.y(), normalB.z());
normalVec.normalize();
dispatcher.getNumManifolds() вместо глобальных коллизий,
чтобы получать только активные контакты.Комбинация manifold points и rayTest позволяет создавать системы детекции столкновений, точного позиционирования объектов и физического взаимодействия с высокой точностью. Правильная работа с нормалями и позициями пересечения является ключевым элементом для симуляции реалистичной физики, реализации реакций на столкновения, системы триггеров и сложных механик в играх и интерактивных приложениях.
Наличие всех этих инструментов делает Ammo.js мощным инструментом для обработки столкновений в браузерных проектах на JavaScript.