Указатели — 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
поведения.
Примеры реализации поведения курсора см. в разделе Assets/MRTK/SDK/Features/UX/Prefabs/Cursors . В частности, DefaultGazeCursor обеспечивает надежную реализацию изменения рисунка курсора на основе контекстного состояния.
Классы указателей по умолчанию
Следующие классы представляют собой готовые указатели MRTK, доступные и определенные в профиле указателей MRTK по умолчанию, описанном выше. Каждая заготовка указателя, предоставляемая в разделе Assets/MRTK/SDK/Features/UX/Prefabs/Pointers , содержит один из присоединенных компонентов указателя.
Дальние указатели
LinePointer
LinePointer, базовый класс указателя, рисует линию от источника входных данных (т. е. контроллера) в направлении указателя и поддерживает приведение одного луча в этом направлении. Как правило, дочерние классы, такие как ShellHandRayPointer
и указатели телепортации, создаются и используются (которые также рисуют линии, чтобы указать, где телепортация в конечном итоге) вместо этого класса, который в первую очередь предоставляет общие функциональные возможности.
Для контроллеров движения, таких как Oculus, Vive и Windows Mixed Reality, поворот будет соответствовать повороту контроллера. Для других контроллеров, таких как HoloLens 2 кисти, поворот соответствует системной позиции руки.
CurvePointer
CurvePointer расширяет класс LinePointer , позволяя выполнять многошаговые приведения лучей вдоль кривой. Этот базовый класс указателей полезен для изогнутых экземпляров, таких как указатели телепортации, где линия последовательно изгибается в параболу.
ShellHandRayPointer
Реализация ShellHandRayPointer, которая распространяется на LinePointer
, используется по умолчанию для профиля указателя MRTK. Заготовка ShellHandRayPointer
DefaultControllerPointer реализует класс .
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
- Коэффициент сглаживания ближнего объекта: коэффициент сглаживания для обнаружения вблизи объектов. Если объект обнаруживается в радиусе ближнего объекта, запрашиваемый радиус становится 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 в фокусе для всех активных указателей.
- Система ввода MRTK распознает событие ввода
- Система ввода MRTK запускает соответствующую функцию интерфейса для события ввода для всех зарегистрированных глобальных обработчиков входных данных.
- Система ввода определяет, какой gameObject находится в фокусе для указателя, который запустил событие.
- Система ввода использует систему событий Unity для запуска соответствующей функции интерфейса для всех соответствующих компонентов в объекте GameObject.
- Если в какой-либо момент входное событие помечено как используемое, процесс завершится, и дальнейшие объекты GameObject не будут получать обратные вызовы.
- Пример. Для компонентов, реализующих интерфейс
IMixedRealityFocusHandler
, будет выполняться поиск объекта GameObject, который получает или теряет фокус. - Примечание. Система событий Unity будет выполнять поиск в родительском GameObject, если в текущем GameObject не найдены компоненты, соответствующие требуемому интерфейсу.
- Пример. Для компонентов, реализующих интерфейс
- Если глобальные обработчики входных данных не зарегистрированы и 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
.
Взаимодействие указателя с помощью редактора
Для событий указателя, обрабатываемых , IMixedRealityPointerHandler
MRTK обеспечивает дополнительное удобство в виде PointerHandler
компонента, что позволяет обрабатывать события указателя непосредственно через события Unity.
Экстент указателя
Дальние указатели имеют параметры, ограничивающие, насколько далеко они будут лучами и взаимодействовать с другими объектами в сцене. По умолчанию это значение равно 10 метров. Это значение было выбрано в соответствии с поведением оболочки HoloLens.
Это можно изменить, обновив DefaultControllerPointer
поля компонента заготовки ShellHandRayPointer
:
Экстент указателя — определяет максимальное расстояние, с которым будут взаимодействовать указатели.
Экстент указателя по умолчанию — определяет длину луча или линии указателя, которые будут отображаться, когда указатель не взаимодействует ни с чем.