AllHitsRayResultCallback: все пересечения

AllHitsRayResultCallback — это класс библиотеки Ammo.js, предназначенный для обнаружения всех пересечений луча с физическими объектами в мире. В отличие от стандартного RayResultCallback, который возвращает только первое пересечение, AllHitsRayResultCallback собирает массив всех точек попадания, что особенно важно для сложных сцен, где нужно учитывать взаимодействие луча с множеством тел.


Создание и инициализация

Для создания экземпляра используется конструктор:

const rayFrom = new Ammo.btVector3(x1, y1, z1);
const rayTo = new Ammo.btVector3(x2, y2, z2);

const allHitsCallback = new Ammo.AllHitsRayResultCallback(rayFrom, rayTo);

Параметры:

  • rayFrom — начальная точка луча (btVector3).
  • rayTo — конечная точка луча (btVector3).

При инициализации автоматически создаются массивы для хранения результатов:

  • m_hitPointWorld — координаты точек пересечения в мировых координатах.
  • m_hitNormalWorld — нормали поверхности в точках пересечения.
  • m_collisionObjects — объекты, с которыми луч пересёкся.

Основные свойства

  1. m_collisionObjects Массив объектов btCollisionObject, с которыми луч пересёкся. Используется для получения физического тела или объекта сцены.

  2. m_hitPointWorld Массив btVector3 точек пересечения. Каждое пересечение добавляется в массив независимо от предыдущих.

  3. m_hitNormalWorld Массив нормалей в точках пересечения (btVector3). Направление нормали показывает ориентацию поверхности.

  4. m_closestHitFraction Фракция расстояния до ближайшего пересечения от rayFrom к rayTo. Используется для фильтрации пересечений по удалённости, если необходимо.

  5. m_collisionFilterGroup / m_collisionFilterMask Настройка фильтров столкновений для ограничения типов объектов, с которыми будет работать луч.


Использование

Для проведения проверки луча используется метод физического мира:

physicsWorld.rayTest(rayFrom, rayTo, allHitsCallback);

После вызова все массивы заполняются, и можно перебрать результаты:

for (let i = 0; i < allHitsCallback.m_hitPointWorld.size(); i++) {
    const point = allHitsCallback.m_hitPointWorld.at(i);
    const normal = allHitsCallback.m_hitNormalWorld.at(i);
    const object = allHitsCallback.m_collisionObjects.at(i);

    console.log("Пересечение:", point.x(), point.y(), point.z());
    console.log("Нормаль:", normal.x(), normal.y(), normal.z());
    console.log("Объект:", object);
}

Особенности:

  • size() возвращает количество элементов в массиве.
  • at(i) позволяет получить элемент по индексу.
  • Каждый массив всегда синхронизирован: m_hitPointWorld[i] соответствует m_hitNormalWorld[i] и m_collisionObjects[i].

Применение фильтров

AllHitsRayResultCallback позволяет отсеивать объекты по группам столкновений:

allHitsCallback.m_collisionFilterGroup = 1; // Группа луча
allHitsCallback.m_collisionFilterMask = 2;  // Маска объектов для пересечения

Эти параметры позволяют пропускать объекты, которые не должны учитываться, и ускоряют вычисления в больших сценах.


Настройка точности и ограничение по длине луча

Для ограничения расстояния до пересечения можно использовать m_closestHitFraction:

allHitsCallback.m_closestHitFraction = 0.8; // 80% от длины луча

Это особенно полезно для оптимизации, когда дальние пересечения не имеют значения.


Сравнение с RayResultCallback

Особенность RayResultCallback AllHitsRayResultCallback
Возвращает только первое пересечение Да Нет
Собирает все пересечения Нет Да
Подходит для сложных сцен Нет Да
Массив точек и нормалей Нет Да

AllHitsRayResultCallback используется в случаях, когда необходимо учитывать все объекты на пути луча, например для лазеров, сенсоров, трассировки лучей в играх или симуляциях.


Оптимизация работы с массивами

Чтобы избежать утечек памяти, после работы с объектами Ammo.js рекомендуется очищать массивы:

allHitsCallback.m_hitPointWorld.clear();
allHitsCallback.m_hitNormalWorld.clear();
allHitsCallback.m_collisionObjects.clear();

И не забывать освобождать ресурсы, когда объект больше не нужен:

Ammo.destroy(allHitsCallback);

Примеры сложного использования

1. Определение всех объектов, пересекаемых лучом в сцене:

const from = new Ammo.btVector3(0, 10, 0);
const to = new Ammo.btVector3(0, -10, 0);
const callback = new Ammo.AllHitsRayResultCallback(from, to);

physicsWorld.rayTest(from, to, callback);

let objectsHit = [];
for (let i = 0; i < callback.m_collisionObjects.size(); i++) {
    objectsHit.push(callback.m_collisionObjects.at(i));
}

2. Определение первого видимого объекта с учётом всех пересечений:

let closestDistance = Infinity;
let closestObject = null;

for (let i = 0; i < callback.m_hitPointWorld.size(); i++) {
    const fraction = callback.m_closestHitFraction;
    if (fraction < closestDistance) {
        closestDistance = fraction;
        closestObject = callback.m_collisionObjects.at(i);
    }
}

Советы по интеграции

  • Использовать AllHitsRayResultCallback для мульти-пересечений, а для простых задач — ClosestRayResultCallback.
  • Перед каждым вызовом rayTest убедиться, что массивы очищены, иначе данные будут накапливаться.
  • Сочетать фильтры групп и масок для ускорения поиска пересечений.
  • Всегда освобождать память через Ammo.destroy после завершения работы с объектом.

Эта система позволяет реализовать точную трассировку лучей, анализировать пересечения со всеми объектами и получать детальные данные о точках контакта и ориентации поверхностей, что делает AllHitsRayResultCallback мощным инструментом для физического моделирования и игровых приложений на JavaScript.