В архитектуре физического движка вычисление столкновений разделяется на два этапа:
Широкая фаза не определяет фактическое столкновение. Её задача — эффективно сократить число проверок, отфильтровав объекты, которые гарантированно не могут пересекаться.
В основе работы лежат ограничивающие объёмы (AABB — Axis-Aligned Bounding Box). Для каждого физического тела рассчитывается прямоугольный параллелепипед, выровненный по мировым осям координат. Пересечение AABB служит критерием для передачи пары в узкую фазу.
В библиотеке Ammo.js, являющейся портом Bullet Physics, реализованы разные алгоритмы широкой фазы. Наиболее часто применяются:
btDbvtBroadphasebtAxisSweep3btDbvtBroadphase основан на динамическом
иерархическом дереве ограничивающих объёмов (Dynamic Bounding Volume
Tree, DBVT). Это адаптивная структура данных, которая
перестраивается по мере движения объектов.
Алгоритм оптимизирован для:
Структура DBVT представляет собой бинарное дерево:
При обновлении положения тела:
Поиск потенциальных пересечений происходит путём обхода дерева и проверки пересечения AABB узлов.
const broadphase = new Ammo.btDbvtBroadphase();
Использование в составе физического мира:
const collisionConfiguration = new Ammo.btDefaultCollisionConfiguration();
const dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration);
const solver = new Ammo.btSequentialImpulseConstraintSolver();
const dynamicsWorld = new Ammo.btDiscreteDynamicsWorld(
dispatcher,
broadphase,
solver,
collisionConfiguration
);
btDbvtBroadphase является дефолтным
выбором для большинства проектов, включая:
btAxisSweep3 реализует классический алгоритм
Sweep and Prune (SAP).
Основная идея:
Если интервалы не пересекаются хотя бы по одной оси, столкновение невозможно.
btAxisSweep3:
Создание:
const worldMin = new Ammo.btVector3(-1000, -1000, -1000);
const worldMax = new Ammo.btVector3(1000, 1000, 1000);
const broadphase = new Ammo.btAxisSweep3(worldMin, worldMax);
В отличие от btDbvtBroadphase, алгоритм SAP требует
заранее определить рабочий объём. Все объекты должны находиться внутри
него.
Если объект выходит за границы:
Поэтому границы должны быть выбраны:
| Характеристика | btDbvtBroadphase | btAxisSweep3 |
|---|---|---|
| Тип структуры | Динамическое дерево | Sweep-and-Prune |
| Границы мира | Не требуются | Обязательны |
| Подходит для | Динамических сцен | Ограниченных сцен |
| Масштабируемость | Высокая | Средняя |
| Стабильность при большом числе движущихся тел | Высокая | Снижается |
При каждом шаге симуляции:
В динамических сценах именно этот этап становится критичным для производительности.
Широкая фаза учитывает:
Пример добавления тела с группами:
dynamicsWorld.addRigidBody(body, group, mask);
Если маска не включает группу другого тела, пара не попадёт даже в широкую фазу.
Статические объекты лучше объединять в compound shape или использовать один большой меш, чтобы сократить число AABB.
Bullet оптимизирует статические тела отдельно, что уменьшает количество проверок.
Границы мира должны:
Ammo.js требует ручного освобождения памяти:
Ammo.destroy(broadphase);
Аналогично необходимо освобождать:
Игнорирование освобождения приводит к утечкам памяти в WebAssembly.
После того как широкая фаза определяет потенциальные пары:
btCollisionDispatcher.Эффективность широкой фазы напрямую влияет на:
При числе тел > 10 000:
btDbvtBroadphase демонстрирует более устойчивое время
шага.btAxisSweep3 может испытывать рост времени
сортировки.В высоконагруженных симуляциях предпочтение обычно отдаётся DBVT.
В Bullet существуют и другие реализации:
bt32BitAxisSweep3btMultiSapBroadphaseОднако в Ammo.js чаще всего используются именно
btDbvtBroadphase и btAxisSweep3, так как они
полностью совместимы с типичным WebAssembly-пайплайном.
Широкая фаза определяет:
Выбор алгоритма не является второстепенной настройкой. Это фундаментальное архитектурное решение, влияющее на поведение всей физической системы в JavaScript-приложении.