Указатели — MRTK2

Указатель

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

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

Конфигурация указателя

Указатели настраиваются как часть системы ввода в MRTK с помощью MixedRealityPointerProfile. Этот тип профиля назначается MixedRealityInputSystemProfile в инспекторе конфигурации MRTK. Профиль указателя определяет курсор, типы указателей, доступные во время выполнения, и то, как эти указатели взаимодействуют друг с другом, чтобы решить, какой из них активен.

  • Pointing Extent — определяет максимальное расстояние, на котором указатель может взаимодействовать с GameObject.

  • Маски слоев raycast — это приоритетный массив LayerMasks, позволяющий определить, с какими возможными объектами GameObjects может взаимодействовать любой указатель, и порядок взаимодействия. Это может быть полезно, чтобы убедиться, что указатели взаимодействуют с элементами пользовательского интерфейса перед другими объектами сцены. Пример профиля указателя

Конфигурация параметров указателя

Конфигурация профиля указателя MRTK по умолчанию включает следующие классы указателей и связанные готовые заготовки. Список указателей, доступных системе во время выполнения, определяется в разделе Параметры указателя в профиле указателя. Разработчики могут использовать этот список для перенастройки существующих указателей, добавления новых указателей или удаления.

Пример профиля параметров указателя

Каждая запись указателя определяется следующим набором данных:

  • Тип контроллера — набор контроллеров, для которые допустим указатель.

    • Например, PokePointer отвечает за "тыкание" объектов пальцем и по умолчанию помечается как поддерживающий только тип контроллера с шарнирной рукой. Экземпляры указателей создаются только тогда, когда контроллер становится доступным, и, в частности , тип контроллера определяет, с какими контроллерами можно создать эту заготовку указателя.
  • Handness — позволяет создать указатель на экземпляр только для определенной руки (слева или вправо).

Примечание

Установка для свойства Handedness элемента Указателя значения Нет фактически отключит его в системе в качестве альтернативы удалению указателя из списка.

  • Prefab указателя — этот ресурс prefab будет создан, когда начнется отслеживание контроллера, соответствующего указанному типу контроллера и степени передачи.

С контроллером можно связать несколько указателей. Например, в DefaultHoloLens2InputSystemProfile (Assets/MRTK/SDK/Profiles/HoloLens2/) шарнирный контроллер руки связан с PokePointer, GrabPointer и DefaultControllerPointer (т. е. лучами рук).

Примечание

MRTK предоставляет набор заготовок указателя в Assets/MRTK/SDK/Features/UX/Prefabs/Pointers. Можно создать новый пользовательский заготовок, если он содержит один из скриптов указателя в Assets/MRTK/SDK/Features/UX/Scripts/Pointers или любой другой скрипт, реализующий IMixedRealityPointer.

Конфигурация курсора

Курсор взгляда можно напрямую настроить с помощью GazeCursorPrefab свойства в MixedRealityInputSystemProfile редакторе . Чтобы настроить курсор, используемый для других указателей, необходимо изменить заготовку, используемую CursorPrefab в поле соответствующего BaseControllerPointerобъекта . Чтобы изменить курсор программным образом, измените BaseCursor свойство соответствующего IMixedRealityPointer поведения.

Свойство prefab cursor

Примеры реализации поведения курсора см. в разделе Assets/MRTK/SDK/Features/UX/Prefabs/Cursors . В частности, DefaultGazeCursor обеспечивает надежную реализацию изменения рисунка курсора на основе контекстного состояния.

Классы указателей по умолчанию

Следующие классы представляют собой готовые указатели MRTK, доступные и определенные в профиле указателей MRTK по умолчанию, описанном выше. Каждая заготовка указателя, предоставляемая в разделе Assets/MRTK/SDK/Features/UX/Prefabs/Pointers , содержит один из присоединенных компонентов указателя.

Стандартные указатели MRTK

Дальние указатели

LinePointer

LinePointer, базовый класс указателя, рисует линию от источника входных данных (т. е. контроллера) в направлении указателя и поддерживает приведение одного луча в этом направлении. Как правило, дочерние классы, такие как ShellHandRayPointer и указатели телепортации, создаются и используются (которые также рисуют линии, чтобы указать, где телепортация в конечном итоге) вместо этого класса, который в первую очередь предоставляет общие функциональные возможности.

Для контроллеров движения, таких как Oculus, Vive и Windows Mixed Reality, поворот будет соответствовать повороту контроллера. Для других контроллеров, таких как HoloLens 2 кисти, поворот соответствует системной позиции руки.

Линия указателя MRTK
CurvePointer

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

ShellHandRayPointer

Реализация ShellHandRayPointer, которая распространяется на LinePointer, используется по умолчанию для профиля указателя MRTK. Заготовка ShellHandRayPointerDefaultControllerPointer реализует класс .

GGVPointer

Также известный как указатель взгляда, жестов и голоса (GGV), GGVPointer обеспечивает взаимодействие в стиле HoloLens 1 и касания, в основном с помощью взгляда и касания воздуха или взгляда и голосового выбора. Положение и направление указателя GGV определяются положением и поворотом головы.

TouchPointer

TouchPointer отвечает за работу с сенсорным вводом Unity (т. е. сенсорным экраном). Это "дальние взаимодействия", потому что акт прикосновения к экрану будет отбрасывает луч от камеры в потенциально далекое место в сцене.

MousePointer

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

Указатель мыши

Примечание

Поддержка мыши недоступна по умолчанию в MRTK, но ее можно включить, добавив новый поставщик входных данных типа MouseDeviceManager во входной профиль MRTK и назначив MixedRealityMouseInputProfile поставщику данных.

Ближайшие указатели

PokePointer

PokePointer используется для взаимодействия с игровыми объектами, которые поддерживают "близкое взаимодействие касания". — объекты GameObject с вложенным NearInteractionTouchable скриптом. В случае с UnityUI этот указатель ищет NearInteractionTouchableUnityUIs. PokePointer использует SphereCast для определения ближайшего сенсорного элемента и используется для управления такими элементами, как нажимаемые кнопки.

При настройке GameObject с NearInteractionTouchable помощью компонента обязательно настройте параметр localForward , чтобы он указывал на переднюю часть кнопки или другой объект, который должен быть ощупывается. Кроме того, убедитесь, что границы ощупляемого объекта соответствуют границам осязаемого объекта.

Полезные свойства poke Pointer:

  • TouchableDistance: максимальное расстояние, на котором может взаимодействовать контактная поверхность.
  • Визуальные элементы: игровой объект, используемый для отрисовки визуального элемента кончика пальца (кольцо на пальце, по умолчанию).
  • Линия: необязательная линия для рисования от кончика пальца к активной поверхности ввода.
  • Poke Layer Masks — приоритетный массив LayerMasks для определения возможных объектов GameObjects, с которыми может взаимодействовать указатель, и порядка взаимодействия. Обратите внимание, что GameObject также должен иметь NearInteractionTouchable компонент для взаимодействия с указателем-мешка.
Указатель на мешок
SpherePointer

SpherePointer использует UnityEngine.Physics.OverlapSphere для идентификации ближайшего NearInteractionGrabbable объекта для взаимодействия, что удобно для "захвата" входных данных, таких ManipulationHandlerкак . Как и в случае с функциональной PokePointer/NearInteractionTouchable парой, для взаимодействия с указателем Sphere объект игры должен содержать компонент, который является скриптом.NearInteractionGrabbable

Указатель захвата

Полезные свойства указателя сферы:

  • Радиус приведения сферы: радиус сферы, используемой для запроса захватываемых объектов.
  • Близкое поле объекта: расстояние поверх радиуса приведения сферы, чтобы определить, находится ли объект рядом с указателем. Общий радиус обнаружения вблизи объекта : радиус приведения сферы + поле вблизи объекта
  • Угол сектора ближнего объекта: угол вокруг прямой оси указателя для запроса ближайших объектов. Делает функцию IsNearObject запроса подобно конусу. По умолчанию задано значение 66 градусов, чтобы соответствовать поведению Hololens 2

Указатель Sphere изменен на запрос только для объектов в направлении вперед

  • Коэффициент сглаживания ближнего объекта: коэффициент сглаживания для обнаружения вблизи объектов. Если объект обнаруживается в радиусе ближнего объекта, запрашиваемый радиус становится near Object Radius * (1 + Near Object Smoothing Factor), чтобы уменьшить чувствительность и затруднить выход объекта из диапазона обнаружения.
  • Захват маски слоев — приоритетный массив LayerMasks для определения возможных объектов GameObject, с которыми может взаимодействовать указатель, и порядка взаимодействия. Обратите внимание, что GameObject также должен иметь NearInteractionGrabbable для взаимодействия с SpherePointer.

    Примечание

    Уровень пространственной осведомленности отключен в заготовке GrabPointer по умолчанию, предоставляемой MRTK. Это делается для снижения влияния на производительность выполнения запроса на перекрытие сферы с пространственной сеткой. Это можно включить, изменив заготовку GrabPointer.

  • Игнорировать коллайдеры Не в FOV — следует ли игнорировать коллайдеры, которые могут находиться рядом с указателем, но на самом деле не находятся в визуальном объекте FOV. Это может предотвратить случайные захваты, и позволит лучам рук включиться, когда вы можете быть рядом с захватом, но не видите его. Visual FOV определяется с помощью конуса, а не типичного frustum по соображениям производительности. Этот конус выравнивается по центру и ориентирован так же, как и у камеры, с радиусом, равным половиной высоты дисплея (или вертикального FOV).
Указатель сферы

Указатели телепорта

  • TeleportPointer вызовет запрос телепорта при выполнении действия (т. е. нажатия кнопки телепорта) для перемещения пользователя.
  • ParabolicTeleportPointer вызовет запрос телепорта при выполнении действия (т. е. нажатия кнопки телепорта) с параболическим лучом линии для перемещения пользователя.
Параболический указатель

Поддержка указателей для платформ смешанной реальности

В следующей таблице подробно описаны типы указателей, которые обычно используются для общих платформ в MRTK. ПРИМЕЧАНИЕ. На эти платформы можно добавлять различные типы указателей. Например, можно добавить указатель Poke или указатель Sphere на виртуальную реальность. Кроме того, устройства виртуальной реальности с геймпадом могут использовать указатель GGV.

Указатель OpenVR: Windows Mixed Reality HoloLens 1 HoloLens 2
ShellHandRayPointer Допустимо Допустимо Допустимо
TeleportPointer Допустимо Допустимо
GGVPointer Допустимо
SpherePointer Допустимо
PokePointer Допустимо

Взаимодействие указателя с помощью кода

Интерфейсы событий указателя

MonoBehaviours, реализующие один или несколько из следующих интерфейсов и назначенные GameObject с , Collider будут получать события взаимодействия указателя в соответствии с соответствующим интерфейсом.

Событие Описание Обработчик
Перед изменением фокуса или изменением фокуса Поднимается как на игровом объекте, теряя фокус, так и на том, который получает его каждый раз, когда указатель меняет фокус. IMixedRealityFocusChangedHandler
Фокус на входе или выходе Возникает на игровом объекте, который получает фокус, когда первый указатель входит в него, и на объекте, который теряет фокус, когда последний указатель покидает его. IMixedRealityFocusHandler
Указатель вниз, перетаскивание, вверх, щелчок Вызывается для нажатия, перетаскивания и отпускания указателя отчета. IMixedRealityPointerHandler
Сенсорный ввод запущен, обновлен или завершен Вызывается указателями с поддержкой сенсорного ввода, такими как PokePointer сообщать об активности сенсорного ввода. IMixedRealityTouchHandler

Примечание

IMixedRealityFocusChangedHandler и IMixedRealityFocusHandler должны обрабатываться в объектах, для которых они вызываются. События фокуса можно получать глобально, но, в отличие от других входных событий, глобальный обработчик событий не блокирует получение событий на основе фокуса (событие будет получено как глобальным обработчиком, так и соответствующим объектом в фокусе).

События ввода указателя в действии

События ввода указателя распознаются и обрабатываются системой ввода MRTK так же, как и обычные события ввода. Разница заключается в том, что события ввода указателя обрабатываются только объектом GameObject в фокусе указателем, который вызвал событие ввода, а также любыми глобальными обработчиками входных данных. Регулярные события ввода обрабатываются GameObjects в фокусе для всех активных указателей.

  1. Система ввода MRTK распознает событие ввода
  2. Система ввода MRTK запускает соответствующую функцию интерфейса для события ввода для всех зарегистрированных глобальных обработчиков входных данных.
  3. Система ввода определяет, какой gameObject находится в фокусе для указателя, который запустил событие.
    1. Система ввода использует систему событий Unity для запуска соответствующей функции интерфейса для всех соответствующих компонентов в объекте GameObject.
    2. Если в какой-либо момент входное событие помечено как используемое, процесс завершится, и дальнейшие объекты GameObject не будут получать обратные вызовы.
      • Пример. Для компонентов, реализующих интерфейс IMixedRealityFocusHandler , будет выполняться поиск объекта GameObject, который получает или теряет фокус.
      • Примечание. Система событий Unity будет выполнять поиск в родительском GameObject, если в текущем GameObject не найдены компоненты, соответствующие требуемому интерфейсу.
  4. Если глобальные обработчики входных данных не зарегистрированы и GameObject не найден с соответствующим компонентом или интерфейсом, система ввода будет вызывать все резервные зарегистрированные обработчики входных данных.

Пример

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

public class ColorTap : MonoBehaviour, IMixedRealityFocusHandler, IMixedRealityPointerHandler
{
    private Color color_IdleState = Color.cyan;
    private Color color_OnHover = Color.white;
    private Color color_OnSelect = Color.blue;
    private Material material;

    private void Awake()
    {
        material = GetComponent<Renderer>().material;
    }

    void IMixedRealityFocusHandler.OnFocusEnter(FocusEventData eventData)
    {
        material.color = color_OnHover;
    }

    void IMixedRealityFocusHandler.OnFocusExit(FocusEventData eventData)
    {
        material.color = color_IdleState;
    }

    void IMixedRealityPointerHandler.OnPointerDown(
         MixedRealityPointerEventData eventData) { }

    void IMixedRealityPointerHandler.OnPointerDragged(
         MixedRealityPointerEventData eventData) { }

    void IMixedRealityPointerHandler.OnPointerClicked(MixedRealityPointerEventData eventData)
    {
        material.color = color_OnSelect;
    }
}

Указатели запросов

Вы можете собрать все активные указатели, просматривая доступные источники входных данных (т. е. доступные контроллеры и входные данные), чтобы определить, какие указатели подключены к ним.

var pointers = new HashSet<IMixedRealityPointer>();

// Find all valid pointers
foreach (var inputSource in CoreServices.InputSystem.DetectedInputSources)
{
    foreach (var pointer in inputSource.Pointers)
    {
        if (pointer.IsInteractionEnabled && !pointers.Contains(pointer))
        {
            pointers.Add(pointer);
        }
    }
}

Основной указатель

Разработчики могут подписаться на событие FocusProviders PrimaryPointerChanged, чтобы получать уведомления о смене основного указателя в фокусе. Это может быть очень полезно, чтобы определить, взаимодействует ли пользователь со сценой в настоящее время с помощью взгляда, луча руки или другого источника входных данных.

private void OnEnable()
{
    var focusProvider = CoreServices.InputSystem?.FocusProvider;
    focusProvider?.SubscribeToPrimaryPointerChanged(OnPrimaryPointerChanged, true);
}

private void OnPrimaryPointerChanged(IMixedRealityPointer oldPointer, IMixedRealityPointer newPointer)
{
    ...
}

private void OnDisable()
{
    var focusProvider = CoreServices.InputSystem?.FocusProvider;
    focusProvider?.UnsubscribeFromPrimaryPointerChanged(OnPrimaryPointerChanged);

    // This flushes out the current primary pointer
    OnPrimaryPointerChanged(null, null);
}

Сцена PrimaryPointerExample (Assets/MRTK/Examples/Demos/Input/Scenes/PrimaryPointer) показывает, как использовать PrimaryPointerChangedHandler для событий для реагирования на новый основной указатель.

Пример основного указателя

Результат указателя

Свойство указателя Result содержит текущий результат запроса сцены, используемого для определения объекта с фокусом. Для указателя луча, аналогичного созданным по умолчанию для контроллеров движения, входного взгляда и лучей рук, он будет содержать расположение и нормальное положение попадания лучей.

private void IMixedRealityPointerHandler.OnPointerClicked(MixedRealityPointerEventData eventData)
{
    var result = eventData.Pointer.Result;
    var spawnPosition = result.Details.Point;
    var spawnRotation = Quaternion.LookRotation(result.Details.Normal);
    Instantiate(MyPrefab, spawnPosition, spawnRotation);
}

Сцена PointerResultExample (Assets/MRTK/Examples/Demos/Input/Scenes/PointerResult/PointerResultExample.unity) показывает, как использовать указатель Result для создания объекта в месте попадания.

Результат указателя

Отключение указателей

Чтобы включить и отключить указатели (например, чтобы отключить луч руки), задайте PointerBehavior для заданного типа указателя с помощью PointerUtils.

// Disable the hand rays
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOff);

// Disable hand rays for the right hand only
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Right);

// Disable the gaze pointer
PointerUtils.SetGazePointerBehavior(PointerBehavior.AlwaysOff);

// Set the behavior to match HoloLens 1
// Note, if on HoloLens 2, you must configure your pointer profile to make the GGV pointer show up for articulated hands.
public void SetHoloLens1()
{
    PointerUtils.SetPokePointerBehavior(PointerBehavior.AlwaysOff, Handedness.Any);
    PointerUtils.SetGrabPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Any);
    PointerUtils.SetRayPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Any);
    PointerUtils.SetGGVBehavior(PointerBehavior.Default);
}

Дополнительные примеры см PointerUtils . в разделе и TurnPointersOnOff .

Взаимодействие указателя с помощью редактора

Для событий указателя, обрабатываемых , IMixedRealityPointerHandlerMRTK обеспечивает дополнительное удобство в виде PointerHandler компонента, что позволяет обрабатывать события указателя непосредственно через события Unity.

Обработчик указателя

Экстент указателя

Дальние указатели имеют параметры, ограничивающие, насколько далеко они будут лучами и взаимодействовать с другими объектами в сцене. По умолчанию это значение равно 10 метров. Это значение было выбрано в соответствии с поведением оболочки HoloLens.

Это можно изменить, обновив DefaultControllerPointer поля компонента заготовки ShellHandRayPointer :

Экстент указателя — определяет максимальное расстояние, с которым будут взаимодействовать указатели.

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

См. также раздел