Определение коллизий и события

Коллизии в Three.js определяют взаимодействие объектов в 3D-пространстве. В отличие от игровых движков, Three.js не предоставляет встроенного физического движка, поэтому разработка столкновений требует применения математических методов, таких как проверка пересечения Bounding Box, Bounding Sphere или кастомных Raycasting-алгоритмов.

Bounding Box (оси-выравненный) — это прямоугольный параллелепипед, полностью охватывающий объект. В Three.js для его создания используется THREE.Box3:

const box = new THREE.Box3().setFromObject(mesh);

Проверка пересечения двух объектов выполняется через метод intersectsBox:

if (box1.intersectsBox(box2)) {
    console.log('Столкновение обнаружено');
}

Bounding Sphere подходит для объектов, близких к сферической форме. Создание сферы выполняется через THREE.Sphere и метод setFromPoints для набора вершин объекта.

const sphere = new THREE.Sphere().setFromPoints(mesh.geometry.attributes.position.array);

Проверка столкновения выполняется через intersectsSphere:

if (sphere1.intersectsSphere(sphere2)) {
    console.log('Сфера столкнулась с другой сферой');
}

Raycasting и определение столкновений

THREE.Raycaster — мощный инструмент для обнаружения пересечений луча с объектами сцены. Это основной способ определения коллизий для мыши и направления движения объектов.

const raycaster = new THREE.Raycaster(origin, direction);
const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) {
    console.log('Объект пересечен лучом', intersects[0].object);
}

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

  • Легко интегрируется с событиями ввода (мышь, касания).
  • Позволяет определять точное место пересечения (point) и нормаль поверхности (face.normal).
  • Поддерживает вложенные объекты благодаря параметру recursive = true.

События в Three.js

Three.js не содержит собственной системы событий для коллизий, поэтому обычно создаются кастомные события через проверку условий и вызов функций обратного вызова.

Пример создания события столкновения между двумя объектами:

function checkCollision(obj1, obj2, callback) {
    const box1 = new THREE.Box3().setFromObject(obj1);
    const box2 = new THREE.Box3().setFromObject(obj2);

    if (box1.intersectsBox(box2)) {
        callback(obj1, obj2);
    }
}

checkCollision(mesh1, mesh2, (a, b) => {
    console.log(`${a.name} столкнулся с ${b.name}`);
});

Можно объединять Raycasting с событиями коллизий для более сложной логики, например, при наведении курсора на объект или при движении персонажа.

Оптимизация коллизий

Проверка столкновений на больших сценах может быть ресурсоёмкой. Основные методы оптимизации:

  • Иерархия объектов (Bounding Volume Hierarchy, BVH): позволяет проверять пересечения сначала с крупными контейнерами, снижая число проверок отдельных объектов.
  • Слой проверки (layers): объекты могут иметь отдельные слои, чтобы исключить ненужные проверки.
  • Сферическая апроксимация для динамических объектов: используется вместо сложных мешей.
  • Кэширование геометрии: заранее вычисленные Box3 и Sphere для статических объектов уменьшают накладные расходы.

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

  1. Игровые персонажи и препятствия Объект персонажа имеет Bounding Box, а объекты сцены (стены, платформы) проверяются на пересечение. При столкновении персонаж останавливается или получает физический отталкивающий эффект.

  2. Навигация камеры Камера может использовать Raycaster для обнаружения стен и предотвращения прохождения через объекты.

  3. Интерактивные объекты С помощью Raycaster реализуется выбор объектов мышью, подсветка при наведении и активация событий при клике.

Расширенные методы

Для сложных физических взаимодействий интегрируются внешние движки, такие как Cannon.js или Ammo.js, а Three.js выступает в роли визуализатора. В этом случае коллизии рассчитываются движком, а сцена обновляется по координатам объектов.

Пример интеграции с Cannon.js:

const shape = new CANNON.Box(new CANNON.Vec3(1, 1, 1));
const body = new CANNON.Body({ mass: 1 });
body.addShape(shape);
world.addBody(body);

// Обновление позиции Three.js объекта по данным физики
mesh.position.copy(body.position);
mesh.quaternion.copy(body.quaternion);

Итоговые рекомендации

  • Использовать Box3 и Sphere для базовых коллизий.
  • Применять Raycaster для интерактивных действий и направления движения.
  • Создавать кастомные события при обнаружении пересечений.
  • Оптимизировать проверки для больших сцен через слои, BVH и кэширование.
  • Для сложной физики подключать внешние движки.

Такой подход обеспечивает точное и эффективное управление столкновениями и событиями в 3D-сценах на Three.js.