RayCastClosest: ближайшее пересечение

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


Основные концепции

В Oimo.js луч задается двумя точками: началом (origin) и направлением (direction). Метод RayCastClosest вычисляет пересечение с телами сцены и возвращает информацию только о первом столкновении, игнорируя все последующие.

Ключевые понятия:

  • origin — вектор начала луча, чаще всего объект OIMO.Vec3.
  • direction — вектор направления и длины луча; длина вектора определяет максимальную дистанцию проверки.
  • collisionMask / collisionGroup — позволяют ограничивать проверку пересечения конкретными группами тел.
  • hitPointWorld — координаты точки пересечения в мировых координатах.
  • hitNormalWorld — нормаль поверхности в точке пересечения, указывающая наружу объекта.
  • hitFraction — доля длины луча, на которой произошло столкновение (значение от 0 до 1).

Создание и использование RayCastClosest

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

const origin = new OIMO.Vec3(0, 10, 0); // точка начала луча
const direction = new OIMO.Vec3(0, -1, 0); // направление вниз
const maxDistance = 100; // максимальная длина луча

Метод rayCastClosest вызывается через объект world:

const result = world.rayCastClosest(origin, direction, maxDistance);

if(result) {
    console.log("Тело:", result.body.name);
    console.log("Точка пересечения:", result.hitPointWorld);
    console.log("Нормаль поверхности:", result.hitNormalWorld);
    console.log("Доля длины луча:", result.hitFraction);
}

Важно: метод возвращает объект с информацией о столкновении или null, если пересечения нет.


Применение collisionMask и collisionGroup

Для оптимизации проверок и фильтрации объектов используется маска столкновений. Каждое тело в Oimo.js может принадлежать определенной группе:

box.collisionGroup = 1; // группа объекта
box.collisionMask = 1;  // с какими группами взаимодействует

При вызове rayCastClosest можно учитывать эти значения, чтобы луч проверял только определенные типы тел:

const result = world.rayCastClosest(origin, direction, maxDistance, 1); // проверка только группы 1

Детали реализации

Метод RayCastClosest внутри Oimo.js работает через итерацию всех тел в мире и проверку пересечения луча с каждым примитивом.

  1. Фильтрация тел — исключаются объекты, не подходящие по collisionMask и collisionGroup.
  2. Проверка примитивов — луч тестируется против всех примитивов тела (box, sphere, capsule).
  3. Сравнение дистанций — сохраняется ближайшая точка пересечения.
  4. Возврат результата — объект RayCastHit содержит body, hitPointWorld, hitNormalWorld, hitFraction.

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


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

  1. Определение поверхности под объектом:
const origin = new OIMO.Vec3(player.position.x, player.position.y, player.position.z);
const direction = new OIMO.Vec3(0, -1, 0);
const hit = world.rayCastClosest(origin, direction, 10);

if(hit) {
    player.groundHeight = hit.hitPointWorld.y;
}
  1. Прицеливание или наведение оружия:
const cameraPosition = camera.getWorldPosition();
const rayDirection = camera.getWorldDirection();
const hit = world.rayCastClosest(cameraPosition, rayDirection, 100);

if(hit) {
    console.log("Первое препятствие:", hit.body.name);
}
  1. Оптимизация поиска ближайшего объекта: Можно комбинировать с collisionMask, чтобы луч не проверял невидимые объекты, что снижает нагрузку на физический движок.

Советы по производительности

  • Сокращение числа проверок: ограничивать длину луча и группы столкновений.
  • Использование простых примитивов: пересечение с сложными мешами требует больше вычислений.
  • Пакетная проверка: если нужно много лучей, их можно проверять циклом и обрабатывать только ближайшие результаты.

Метод RayCastClosest в Oimo.js обеспечивает быстрый и точный способ определения ближайшего столкновения луча с физическими объектами, позволяя эффективно реализовывать механики взаимодействия, навигации и обнаружения объектов в 3D-пространстве.