Библиотека Ammo.js является JavaScript-портом
физического движка Bullet Physics, предоставляя мощные
средства для симуляции твердых тел, столкновений и динамики в 3D. Одной
из ключевых возможностей является проведение лучевых тестов (ray
casting) для определения пересечений объектов в сцене. Основными
инструментами для этого являются метод
btCollisionWorld::rayTest и класс
ClosestRayResultCallback.
Метод btCollisionWorld::rayTest выполняет
лучевой запрос в физическом мире, проверяя пересечения
луча с объектами сцены. Он принимает на вход:
from), объект
типа btVector3.to), объект типа
btVector3.Пример базовой структуры вызова:
let from = new Ammo.btVector3(0, 10, 0);
let to = new Ammo.btVector3(0, -10, 0);
let rayCallback = new Ammo.ClosestRayResultCallback(from, to);
physicsWorld.rayTest(from, to, rayCallback);
В этом коде physicsWorld — это экземпляр
btCollisionWorld или
btDiscreteDynamicsWorld.
ClosestRayResultCallbackClosestRayResultCallback используется для получения
самого ближайшего пересечения луча с объектами.
Основные свойства и методы:
hasHit() — возвращает
true, если луч пересек объект.get_m_hitPointWorld() — возвращает
точку пересечения в мировых координатах (btVector3).get_m_hitNormalWorld() — нормаль
поверхности в точке столкновения.get_m_collisionObject() — объект
столкновения (btCollisionObject).set_m_collisionFilterMask(mask) и
set_m_collisionFilterGroup(group) —
фильтры для ограничения поиска столкновений по группам и маскам.Пример обработки результатов:
if (rayCallback.hasHit()) {
let collisionPoint = rayCallback.get_m_hitPointWorld();
let collisionNormal = rayCallback.get_m_hitNormalWorld();
let collidedObject = rayCallback.get_m_collisionObject();
console.log("Точка столкновения:", collisionPoint.x(), collisionPoint.y(), collisionPoint.z());
console.log("Нормаль столкновения:", collisionNormal.x(), collisionNormal.y(), collisionNormal.z());
}
Для оптимизации и точного контроля над лучевыми тестами можно задавать фильтры. Каждое тело в Ammo.js принадлежит определённой группе столкновений и имеет маску столкновений. Пример:
rayCallback.set_m_collisionFilterGroup(1); // Группа луча
rayCallback.set_m_collisionFilterMask(2); // Маска объектов, с которыми разрешено столкновение
Это позволяет игнорировать неинтересные объекты и уменьшить нагрузку на физический движок.
ClosestRayResultCallback возвращает только
ближайшее пересечение. Для получения всех пересечений
используется AllHitsRayResultCallback.addRigidBody или аналогичные методы.btVector3 и callback объекты
необходимо освобождать через Ammo.destroy() для
предотвращения утечек памяти.btVector3. Для интеграции с
Three.js или другими движками их нужно конвертировать в массив или
объект в формате {x, y, z}.let from = new Ammo.btVector3(player.position.x, player.position.y, player.position.z);
let to = new Ammo.btVector3(player.position.x, player.position.y - 100, player.position.z);
let rayCallback = new Ammo.ClosestRayResultCallback(from, to);
physicsWorld.rayTest(from, to, rayCallback);
if (rayCallback.hasHit()) {
let point = rayCallback.get_m_hitPointWorld();
let normal = rayCallback.get_m_hitNormalWorld();
let hitObj = rayCallback.get_m_collisionObject();
console.log(`Объект столкновения: ${hitObj}`);
console.log(`Точка: (${point.x()}, ${point.y()}, ${point.z()})`);
console.log(`Нормаль: (${normal.x()}, ${normal.y()}, ${normal.z()})`);
}
Ammo.destroy(rayCallback);
Ammo.destroy(from);
Ammo.destroy(to);
В этом примере создается луч от позиции игрока вниз, проверяется пересечение с любым объектом в мире, извлекаются точка контакта, нормаль и сам объект. После завершения все временные объекты освобождаются, что критично для работы в браузере с большим количеством физических объектов.
btVector3 внутри игрового
цикла, переиспользуя объекты.AllHitsRayResultCallback или
кастомные callback.Эти инструменты позволяют создавать сложные физические взаимодействия, реализовывать точное управление столкновениями и улучшать реализм физики в браузерных 3D-приложениях на JavaScript.