Ввод взгляда головы и взгляда в DirectX
Примечание
Эта статья относится к устаревшим собственным API WinRT. Для новых проектов собственных приложений рекомендуется использовать API OpenXR.
В Windows Mixed Reality для определения того, что смотрит пользователь, используется ввод взгляда и головы. Данные можно использовать для управления основными моделями ввода, такими как головный взгляд и фиксация, а также для предоставления контекста для различных типов взаимодействия. Существует два типа векторов взгляда, доступных через API: взгляд на голову и взгляд. Оба варианта предоставляются в виде трехмерного луча с источником и направлением. Затем приложения могут транслировать свои сцены или реальный мир и определять, на что нацелен пользователь.
Head-gaze представляет направление, в которое направлена голова пользователя. Думайте о взгляде на голову как о положении и направлении вперед самого устройства, а положение — как центральную точку между двумя дисплеями. Головной взгляд доступен на всех Смешанная реальность устройствах.
Взгляд представляет направление, в которое смотрят глаза пользователя. Источник находится между глазами пользователя. Она доступна на Смешанная реальность устройствах с системой отслеживания взгляда.
Лучи головы и взгляда доступны через API SpatialPointerPose . Вызовите SpatialPointerPose::TryGetAtTimestamp , чтобы получить новый объект SpatialPointerPose в указанной метке времени и системе координат. Этот объект SpatialPointerPose содержит направление и источник направления направления. Он также содержит источник и направление взгляда, если доступно отслеживание взгляда.
Поддержка устройств
Компонент | HoloLens (1-го поколения) | HoloLens 2 | Иммерсивные гарнитуры |
Направление головы | ✔️ | ✔️ | ✔️ |
Взгляд | ❌ | ✔️ | ❌ |
Использование взгляда головы
Чтобы получить доступ к взгляду головы, начните с вызова SpatialPointerPose::TryGetAtTimestamp , чтобы получить новый объект SpatialPointerPose. Передайте следующие параметры.
- Объект SpatialCoordinateSystem, представляющий нужную систему координат для взгляда головы. Это представляется переменной координаты в следующем коде. Дополнительные сведения см. в руководстве разработчика по системам координат .
- Метка времени, представляющая точное время запрашиваемой позиции головы. Как правило, используется метка времени, соответствующая времени отображения текущего кадра. Эту прогнозируемую метку времени отображения можно получить из объекта HolographicFramePrediction , доступного через текущий HolographicFrame. Этот объект HolographicFramePrediction представлен переменной прогнозирования в следующем коде.
Когда у вас есть допустимый SpatialPointerPose, положение головы и направление вперед становятся доступными в виде свойств. В следующем коде показано, как получить к ним доступ.
using namespace winrt::Windows::UI::Input::Spatial;
using namespace winrt::Windows::Foundation::Numerics;
SpatialPointerPose pointerPose = SpatialPointerPose::TryGetAtTimestamp(coordinateSystem, prediction.Timestamp());
if (pointerPose)
{
float3 headPosition = pointerPose.Head().Position();
float3 headForwardDirection = pointerPose.Head().ForwardDirection();
// Do something with the head-gaze
}
Использование взгляда
Чтобы пользователи использовали ввод взгляда, каждый пользователь должен пройти калибровку пользователя отслеживания взгляда при первом использовании устройства. API взгляда похож на взгляд головы. Он использует тот же API SpatialPointerPose , который предоставляет источник и направление луча, которое можно выполнять по сцене. Единственное отличие заключается в том, что перед его использованием необходимо явно включить отслеживание взгляда:
- Запросите у пользователя разрешение на использование отслеживания взгляда в приложении.
- Включите возможность "Входные данные взгляда" в манифесте пакета.
Запрос доступа к входным данным взгляда
Когда приложение запускается, вызовите EyesPose::RequestAccessAsync , чтобы запросить доступ к отслеживанию взгляда. При необходимости система запросит пользователя и возвратит GazeInputAccessStatus::Allowed после предоставления доступа. Это асинхронный вызов, поэтому для него требуется дополнительное управление. В следующем примере выполняется вращение отсоединяемого потока std::thread для ожидания результата, который сохраняется в переменной-члене с именем m_isEyeTrackingEnabled.
using namespace winrt::Windows::Perception::People;
using namespace winrt::Windows::UI::Input;
std::thread requestAccessThread([this]()
{
auto status = EyesPose::RequestAccessAsync().get();
if (status == GazeInputAccessStatus::Allowed)
m_isEyeTrackingEnabled = true;
else
m_isEyeTrackingEnabled = false;
});
requestAccessThread.detach();
Запуск отсоединяемого потока — это только один из вариантов обработки асинхронных вызовов. Вы также можете использовать новые функции co_await , поддерживаемые C++/WinRT. Вот еще один пример запроса разрешения пользователя:
- EyesPose::IsSupported() позволяет приложению запускать диалоговое окно разрешений только при наличии средства отслеживания взгляда.
- GazeInputAccessStatus m_gazeInputAccessStatus; Это необходимо, чтобы предотвратить повторное появление запроса на получение разрешений.
GazeInputAccessStatus m_gazeInputAccessStatus; // This is to prevent popping up the permission prompt over and over again.
// This will trigger to show the permission prompt to the user.
// Ask for access if there is a corresponding device and registry flag did not disable it.
if (Windows::Perception::People::EyesPose::IsSupported() &&
(m_gazeInputAccessStatus == GazeInputAccessStatus::Unspecified))
{
Concurrency::create_task(Windows::Perception::People::EyesPose::RequestAccessAsync()).then(
[this](GazeInputAccessStatus status)
{
// GazeInputAccessStatus::{Allowed, DeniedBySystem, DeniedByUser, Unspecified}
m_gazeInputAccessStatus = status;
// Let's be sure to not ask again.
if(status == GazeInputAccessStatus::Unspecified)
{
m_gazeInputAccessStatus = GazeInputAccessStatus::DeniedBySystem;
}
});
}
Объявление возможности "Входные данные взгляда "
Дважды щелкните файл appxmanifest в Обозреватель решений. Затем перейдите к разделу Возможности и проверка функцию "Входные данные взгляда".
При этом в раздел Пакет в файле appxmanifest будут добавлены следующие строки:
<Capabilities>
<DeviceCapability Name="gazeInput" />
</Capabilities>
Получение луча взгляда
Получив доступ к ET, вы можете захватить луч взгляда каждый кадр. Как и в случае с головным взглядом, получите SpatialPointerPose , вызвав SpatialPointerPose::TryGetAtTimestamp с требуемой меткой времени и системой координат. SpatialPointerPose содержит объект EyesPose через свойство Eyes . Это значение не равно NULL, только если включена функция отслеживания взгляда. Оттуда можно проверка, есть ли у пользователя на устройстве калибровка отслеживания взгляда, вызвав EyesPose::IsCalibrationValid. Затем используйте свойство Gaze , чтобы получить Объект SpatialRay , содержащий положение и направление взгляда. Свойство Gaze иногда может иметь значение NULL, поэтому не забудьте проверка для этого. Это может произойти, если откалиброванный пользователь временно закрывает глаза.
В следующем коде показано, как получить доступ к лучу взгляда.
using namespace winrt::Windows::UI::Input::Spatial;
using namespace winrt::Windows::Foundation::Numerics;
SpatialPointerPose pointerPose = SpatialPointerPose::TryGetAtTimestamp(coordinateSystem, prediction.Timestamp());
if (pointerPose)
{
if (pointerPose.Eyes() && pointerPose.Eyes().IsCalibrationValid())
{
if (pointerPose.Eyes().Gaze())
{
auto spatialRay = pointerPose.Eyes().Gaze().Value();
float3 eyeGazeOrigin = spatialRay.Origin;
float3 eyeGazeDirection = spatialRay.Direction;
// Do something with the eye-gaze
}
}
}
Резервный вариант, когда отслеживание взгляда недоступно
Как упоминалось в нашей документации по проектированию отслеживания взгляда, как разработчики, так и разработчики должны знать об экземплярах, в которых данные отслеживания взгляда могут быть недоступны.
Существуют различные причины недоступности данных.
- Пользователь не откалибровывается
- Пользователь отказал приложению в доступе к данным отслеживания глаз
- Временные помехи, такие как пятно на визоре HoloLens или волосы, закрывающие глаза пользователя.
Хотя некоторые ИЗ API уже упоминались в этом документе, ниже приведены краткие сведения о том, как определить, что отслеживание взгляда доступно в качестве краткого справочника:
Убедитесь, что система поддерживает отслеживание взгляда. Вызовите следующий метод: Windows.Perception.Люди. EyesPose.IsSupported()
Убедитесь, что пользователь откалиброван. Вызовите следующее свойство: Windows.Perception.Люди. EyesPose.IsCalibrationValid
Убедитесь, что пользователь предоставил приложению разрешение на использование данных отслеживания взгляда: Получите текущий объект GazeInputAccessStatus. Пример того, как это сделать, описан в разделе Запрос доступа к входным данным взгляда.
Вы также можете проверка, чтобы данные отслеживания взгляда не устарели, добавив время ожидания между полученными обновлениями данных отслеживания взгляда и в противном случае откат к взгляду головы, как описано ниже. Дополнительные сведения см. в разделе Рекомендации по проектированию резервных копий.
Сопоставление взгляда с другими входными данными
Иногда может оказаться, что вам требуется SpatialPointerPose , соответствующий событию в прошлом. Например, если пользователь выполняет air tap, вашему приложению может потребоваться узнать, на что он смотрел. Для этой цели простое использование SpatialPointerPose::TryGetAtTimestamp с прогнозируемым временем кадра будет неточным из-за задержки между обработкой системных входных данных и временем отображения. Кроме того, если используется взгляд для нацеливания, наши глаза, как правило, двигаться дальше еще до завершения действия фиксации. Это не проблема простого касания воздуха, но становится более важным при сочетании длинных голосовых команд с быстрыми движениями глаз. Один из способов обработки этого сценария — выполнить дополнительный вызов SpatialPointerPose::TryGetAtTimestamp, используя метку времени журнала, соответствующую входному событию.
Однако для входных данных, которые маршрутит через SpatialInteractionManager, существует более простой метод. SpatialInteractionSourceState имеет собственную функцию TryGetAtTimestamp. Вызов, который обеспечит идеально коррелированную функцию SpatialPointerPose без догадок. Дополнительные сведения о работе с SpatialInteractionSourceStates см. в разделе Руки и контроллеры движения в документации по DirectX.
Калибровка
Чтобы отслеживание взгляда работало точно, каждый пользователь должен пройти калибровку пользователя отслеживания взгляда. Это позволяет устройству настроить систему для более удобного и более высокого качества просмотра для пользователя и обеспечить точное отслеживание взгляда в то же время. Разработчикам не нужно ничего делать, чтобы управлять калибровкой пользователей. Система гарантирует, что пользователю будет предложено откалибровать устройство в следующих случаях:
- Пользователь использует устройство впервые.
- Пользователь ранее отказался от калибровки.
- Не удалось выполнить калибровку в последний раз, когда пользователь работал с устройством.
Разработчики должны обеспечить надлежащую поддержку для пользователей, у которых данные отслеживания взгляда могут быть недоступны. Дополнительные сведения о рекомендациях по резервным решениям см. в статье Отслеживание взгляда на HoloLens 2.