Лучевой ввод (ray input) с контроллеров

Лучевой ввод в A-Frame позволяет взаимодействовать с объектами виртуальной сцены с помощью направленных лучей, исходящих из контроллеров VR, указателей мыши или других устройств. Он используется для выбора, активации и манипуляции объектами на расстоянии, заменяя традиционный физический контакт. В основе лежит компонент raycaster, который генерирует лучи и отслеживает пересечения с объектами сцены.


Компонент raycaster

raycaster является ключевым инструментом для реализации лучевого ввода. Основные свойства компонента:

  • objects — CSS-селектор или список объектов, с которыми луч будет взаимодействовать (.clickable, #target).
  • far / near — максимальная и минимальная длина луча в единицах сцены (по умолчанию far: 1000, near: 0.1).
  • showLine — если true, визуально отображает луч в виде линии.
  • direction — вектор направления луча, обычно 0 0 -1 для контроллера, направленного вперед.

Пример подключения к контроллеру:

<a-entity id="right-hand" laser-controls="hand: right">
  <a-entity raycaster="objects: .interactable; showLine: true"></a-entity>
</a-entity>

В этом примере луч создаётся от правого контроллера и взаимодействует со всеми объектами с классом interactable.


Перехват событий луча

Лучевой ввод в A-Frame генерирует несколько событий, которые можно использовать для реакции на пересечения объектов:

  • raycaster-intersected — срабатывает, когда луч впервые пересёк объект.
  • raycaster-intersected-cleared — срабатывает, когда объект больше не пересекается лучом.
  • click / mouseenter / mouseleave — работают в сочетании с cursor для имитации взаимодействия.

Пример добавления обработчиков событий на объект:

<a-box class="interactable" position="0 1.5 -3" color="#4CC3D9">
</a-box>

<script>
  const box = document.querySelector('.interactable');
  box.addEventListener('raycaster-intersected', () => {
    box.setAttribute('color', '#EF2D5E');
  });
  box.addEventListener('raycaster-intersected-cleared', () => {
    box.setAttribute('color', '#4CC3D9');
  });
</script>

Использование контроллеров VR

A-Frame поддерживает стандартные контроллеры через компонент laser-controls или hand-controls. Луч создаётся автоматически, но можно кастомизировать его свойства. Основные параметры:

  • hand — определяет руку (left или right).
  • model — если true, отображается 3D-модель контроллера.
  • rayOrigin — точка старта луча (tip или controller).

Пример кастомного луча от контроллера:

<a-entity laser-controls="hand: left" raycaster="objects: .clickable; showLine: true">
</a-entity>

Комбинация с cursor

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

  • fuse — если true, запускается таймер активации при наведении.
  • fuseTimeout — продолжительность таймера в миллисекундах.

Пример:

<a-entity laser-controls="hand: right" raycaster="objects: .clickable">
  <a-entity cursor="fuse: true; fuseTimeout: 1500"></a-entity>
</a-entity>

Отслеживание пересечений через компонент raycaster в JavaScript

Для динамических сцен часто нужно обрабатывать пересечения программно. A-Frame предоставляет API:

const raycasterEl = document.querySelector('[raycaster]');
const intersects = raycasterEl.components.raycaster.intersections;
intersects.forEach(intersect => {
  console.log('Пересечение с объектом:', intersect.object.el.id);
});

Метод intersections возвращает массив объектов пересечения с информацией о точке пересечения, нормали поверхности и расстоянии.


Оптимизация и фильтрация объектов

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

  • CSS-классы.clickable, .interactive.
  • Атрибутыdata-raycastable="true".
  • Слои — через компонент raycaster можно исключать определённые объекты, чтобы улучшить производительность.

Пример:

<a-entity raycaster="objects: [data-raycastable='true']; far: 10"></a-entity>

Визуализация луча

Встроенный метод showLine: true создаёт линию от источника луча до объекта пересечения. Для кастомизации можно использовать компонент line:

<a-entity id="ray" line="start: 0 0 0; end: 0 0 -1; color: red"></a-entity>

Программно можно обновлять конец линии в зависимости от пересечения:

rayEl.setAttribute('line', 'end', `${intersectPoint.x} ${intersectPoint.y} ${intersectPoint.z}`);

Лучевой ввод с нескольких контроллеров

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

<a-entity laser-controls="hand: left" raycaster="objects: .interactable"></a-entity>
<a-entity laser-controls="hand: right" raycaster="objects: .interactable"></a-entity>

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


Применение в интерактивных сценах

Лучевой ввод широко используется для:

  • Навигации по меню VR.
  • Выбора объектов и активации функций.
  • Манипуляций с 3D-моделями (перетаскивание, вращение, масштабирование).
  • Совмещения с эффектами визуальной обратной связи (подсветка, анимация, звук).

В сочетании с другими компонентами A-Frame, такими как animation, interaction, state, лучевой ввод создаёт гибкую и мощную систему взаимодействия без необходимости физического контакта.