Ray и RaycastResult

Ray в Cannon.js представляет собой луч, который используется для обнаружения пересечений с телами в физическом мире. Основная цель луча — проверка коллизий и получение информации о том, с какими объектами он пересекается, на каком расстоянии и в какой точке. Ray используется для реализации таких функций, как лазерные указки, детекторы столкновений и сенсоры объектов.

Создание и настройка Ray

Объект луча создаётся с помощью конструктора CANNON.Ray:

const ray = new CANNON.Ray(from, to);
  • from — начальная точка луча (CANNON.Vec3).
  • to — конечная точка луча (CANNON.Vec3).

Луч может быть настроен для различных целей:

ray.skipBackfaces = true; // игнорирование обратных граней
ray.collisionFilterMask = 1; // маска для фильтрации тел по группам
ray.collisionFilterGroup = 1; // группа, к которой принадлежит луч
ray.mode = CANNON.Ray.ALL; // режим проверки пересечений
  • mode может принимать значения:

    • CANNON.Ray.ANY — возвращает первое пересечение.
    • CANNON.Ray.CLOSEST — возвращает ближайшее пересечение.
    • CANNON.Ray.ALL — возвращает все пересечения.

Методы Ray

1. intersectBodies Метод проверяет пересечение луча с массивом тел:

ray.intersectBodies(bodies, resultCallback);
  • bodies — массив объектов CANNON.Body.
  • resultCallback — функция, вызываемая для каждого пересечения. Принимает объект RaycastResult.

2. intersectBody Проверяет пересечение с одним телом:

ray.intersectBody(body, resultCallback);

3. intersectWorld Проверяет пересечение с телами в мире Cannon.js:

ray.intersectWorld(world, options);
  • world — экземпляр CANNON.World.
  • options — объект с настройками: mode, skipBackfaces, collisionFilterMask, collisionFilterGroup.

RaycastResult

Объект RaycastResult содержит полную информацию о пересечении луча с телом:

const result = new CANNON.RaycastResult();

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

  • body — тело (CANNON.Body), с которым произошло пересечение.
  • shape — форма (CANNON.Shape), с которой произошло пересечение.
  • hitPointWorld — точка пересечения в мировых координатах (CANNON.Vec3).
  • hitNormalWorld — нормаль поверхности в точке пересечения (CANNON.Vec3), направленная от поверхности к источнику луча.
  • distance — расстояние от начала луча до точки пересечения.
  • hasHit — булевое значение, указывающее, было ли пересечение.

Пример использования:

const result = new CANNON.RaycastResult();
ray.intersectWorld(world, {
    mode: CANNON.Ray.CLOSEST,
    result: result
});
if (result.hasHit) {
    console.log("Тело:", result.body.id);
    console.log("Точка пересечения:", result.hitPointWorld);
    console.log("Нормаль:", result.hitNormalWorld);
}

Практические советы

  • Оптимизация: для массовых проверок пересечений лучше использовать Ray.ALL с массивом тел, но фильтровать по группам и маскам, чтобы снизить нагрузку.
  • Точность: для сложных тел с несколькими формами важно проверять нормаль (hitNormalWorld), чтобы правильно вычислять реакции на столкновения.
  • Направление луча: длина луча вычисляется как расстояние между from и to. Для бесконечного луча можно масштабировать to по направлению векторного направления.
  • Обработка множественных пересечений: при использовании Ray.ALL результат можно хранить в массиве RaycastResult, чтобы анализировать все точки пересечения и выбирать необходимую для логики игры или симуляции.

Примеры применения

  1. Детектирование пола под персонажем:
const from = new CANNON.Vec3(player.position.x, player.position.y, player.position.z);
const to = new CANNON.Vec3(player.position.x, player.position.y - 10, player.position.z);
const ray = new CANNON.Ray(from, to);
const result = new CANNON.RaycastResult();
ray.intersectWorld(world, { mode: CANNON.Ray.CLOSEST, result: result });

if (result.hasHit) {
    player.onGro und = true;
    player.groundNormal = result.hitNormalWorld.clone();
}
  1. Лазерный луч для стрельбы:
const ray = new CANNON.Ray(shooter.position, target.position);
ray.mode = CANNON.Ray.ANY;
ray.intersectWorld(world, { result: result });

if (result.hasHit) {
    applyDamage(result.body, damage);
}
  1. Сенсорные системы для роботов:
  • Создание сетки лучей вокруг робота.
  • Проверка всех пересечений с препятствиями.
  • Использование нормалей для корректного обхода объектов.

Взаимодействие с другими компонентами Cannon.js

  • Bodies и Shapes: Ray взаимодействует со всеми формами (Box, Sphere, ConvexPolyhedron, Trimesh), учитывая их трансформации.
  • Collision Groups: Совмещение масок луча и тел позволяет избирательно проверять пересечения.
  • World: Ray использует структуру Broadphase для ускорения поиска столкновений, что критично для больших сцен с множеством тел.

Ray и RaycastResult образуют мощный инструмент для анализа сцены и реализации сложной физической логики, позволяя получать точные точки пересечения, вычислять нормали и корректно реагировать на коллизии. Их правильное использование обеспечивает реалистичные взаимодействия в 3D-пространстве.