Intersection и intersectedEl

В A-Frame взаимодействие с объектами сцены часто строится вокруг лучевого кастинга (raycasting), когда луч, исходящий от контроллера, курсора или камеры, проверяет пересечение с объектами. Два ключевых понятия в этом процессе — это intersection и intersectedEl, которые позволяют отслеживать, какие элементы сцены были задеты лучом.


Intersection: структура и содержание

Intersection — это объект, описывающий факт пересечения луча с элементом сцены. Он формируется системой raycaster и содержит всю необходимую информацию для работы с объектами, включая координаты, нормали поверхности и сам элемент.

Ключевые свойства объекта intersection:

  • point — точка пересечения в мировых координатах. Это THREE.Vector3, который позволяет точно определить позицию контакта луча с объектом.
  • distance — расстояние от начала луча до точки пересечения. Полезно для определения ближайшего объекта при нескольких попаданиях.
  • face — информация о грани, с которой произошло пересечение, включая нормаль и индексы вершин.
  • faceIndex — индекс грани, пересечение с которой произошло.
  • object — трехмерный объект (THREE.Object3D) из сцены, с которым произошло пересечение.
  • uv — координаты текстуры на точке пересечения, если объект использует материал с текстурой.
  • instanceId — для инстансированных объектов, идентификатор конкретного экземпляра.

Пример структуры объекта intersection:

{
  "distance": 5.2,
  "point": {"x": 1, "y": 2, "z": -3},
  "face": {"a": 0, "b": 1, "c": 2, "normal": {"x":0,"y":1,"z":0}},
  "object": "[object Object]"
}

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


intersectedEl: ссылка на A-Frame-элемент

intersectedEl — это свойство компонентов, работающих с raycaster (например, cursor или кастомные контроллеры), которое указывает на DOM-элемент A-Frame, пересечённый лучом. Оно работает на уровне элемента <a-entity>, а не чистого объекта THREE.js, что удобно для интеграции с событиями A-Frame.

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

  • При наличии пересечения содержит ссылку на <a-entity> или <a-mesh> в сцене.
  • Если луч не пересекает объект, значение intersectedEl становится null.
  • Обновляется каждый кадр, что позволяет динамически реагировать на перемещение курсора или контроллера.
  • Используется совместно с событиями mouseenter, mouseleave, click, что делает интерактивность интуитивной.

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

<a-entity id="cameraRig">
  <a-camera>
    <a-cursor id="cursor"></a-cursor>
  </a-camera>
</a-entity>

<a-box position="0 1 -5" color="blue" id="box"></a-box>
const cursorEl = document.querySelector('#cursor');

cursorEl.addEventListener('mouseenter', (evt) => {
  if (evt.detail.intersectedEl) {
    evt.detail.intersectedEl.setAttribute('color', 'red');
  }
});

cursorEl.addEventListener('mouseleave', (evt) => {
  if (evt.detail.intersectedEl) {
    evt.detail.intersectedEl.setAttribute('color', 'blue');
  }
});

Здесь intersectedEl обеспечивает удобную ссылку на объект сцены без необходимости работать с низкоуровневыми объектами THREE.js.


Связь между intersection и intersectedEl

  • intersection предоставляет точную геометрическую информацию: координаты, нормали, текстуры.
  • intersectedEl обеспечивает ссылку на A-Frame-элемент, что удобно для манипуляции DOM-атрибутами и компонентами.
  • В событиях A-Frame intersection доступен через evt.detail.intersection, а intersectedEl через evt.detail.intersectedEl.

Пример расширенного взаимодействия:

cursorEl.addEventListener('click', (evt) => {
  const intersected = evt.detail.intersectedEl;
  const intersection = evt.detail.intersection;

  if (intersected) {
    console.log('Clicked entity:', intersected.id);
    console.log('Intersection point:', intersection.point);
    intersected.setAttribute('position', {
      x: intersection.point.x,
      y: intersection.point.y + 1,
      z: intersection.point.z
    });
  }
});

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


Особенности работы с массивом пересечений

Raycaster в A-Frame может пересекать несколько объектов одновременно. В этом случае:

  • Свойство intersections содержит массив объектов intersection, отсортированных по расстоянию от начала луча.
  • intersectedEl автоматически указывает на первый элемент в списке, ближайший к лучу.
  • Возможна обработка всех объектов массива, что полезно для комплексных сцен с наложенными объектами.

Пример обхода всех пересечений:

cursorEl.addEventListener('raycaster-intersection', (evt) => {
  evt.detail.intersections.forEach(intersect => {
    console.log('Hit entity:', intersect.object.el.id, 'at', intersect.point);
  });
});

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

  • Использовать intersectedEl для управления свойствами A-Frame: цвет, видимость, включение/выключение компонентов.
  • Использовать intersection для точного позиционирования и анимаций, когда важно знать координаты пересечения или нормали поверхности.
  • Не полагаться только на intersectedEl, если необходимо работать с инстансированными или сложными THREE.js объектами, которые не имеют прямой привязки к <a-entity>.

Эти механизмы позволяют строить интерактивные VR/AR сцены с точной геометрией и удобной работой на уровне элементов A-Frame, обеспечивая высокую гибкость при проектировании взаимодействий.