Ввод взгляда головы и взгляда в DirectX

Примечание

Эта статья относится к устаревшим собственным API WinRT. Для новых проектов собственных приложений рекомендуется использовать API OpenXR.

В Windows Mixed Reality, входные данные взгляда и взгляда на голову используются для определения того, что смотрит пользователь. Вы можете использовать эти данные для управления основными моделями ввода, такими как взгляд головы и фиксация, и предоставлять контекст для различных типов взаимодействия. Существует два типа векторов взгляда, доступных через API: взгляд на голову и взгляд. Оба предоставляются в виде трехмерного луча с происхождением и направлением. Затем приложения могут выполнять трансляцию в свои сцены или реальный мир и определять, на что ориентирован пользователь.

Взгляд на голову представляет направление, в которое указывает голова пользователя. Подумайте о взгляде головы в качестве положения и направления вперед самого устройства, с положением в качестве центральной точки между двумя дисплеями. Головной взгляд доступен на всех устройствах Смешанная реальность.

Взгляд на глаза представляет направление, к которому смотрят глаза пользователя. Источник находится между глазами пользователя. Она доступна на Смешанная реальность устройствах, включающих систему отслеживания глаз.

Лучи головы и взгляда доступны через 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 взгляда на голову. Он использует тот же API SpatialPointerPose , который предоставляет источник и направление лучей, которые можно выполнять в сцене. Единственное отличие заключается в том, что перед его использованием необходимо явно включить отслеживание глаз:

  1. Запросите разрешение пользователя на использование отслеживания глаз в приложении.
  2. Включите функцию "Входные данные взгляда" в манифесте пакета.

Запрос доступа к входным данным взгляда

При запуске приложения вызовите 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-интерфейсы уже упоминались в этом документе, в следующем примере мы предоставляем сводку по обнаружению того, что отслеживание глаз доступно в качестве краткой справки:

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


Сопоставление взгляда с другими входными данными

Иногда может оказаться, что требуется SpatialPointerPose , соответствующий событию в прошлом. Например, если пользователь выполняет air Tap, ваше приложение может узнать, что они просматривали. Для этого просто использование SpatialPointerPose::TryGetAtTimestamp с прогнозируемым временем кадров будет неточным из-за задержки между обработкой системных входных данных и временем отображения. Кроме того, если для нацеливания используется взгляд, наши глаза, как правило, двигаться дальше даже до завершения действия фиксации. Это меньше проблемы для простого касания воздуха, но становится более критическим при объединении длинных голосовых команд с быстрым движением глаз. Одним из способов обработки этого сценария является выполнение дополнительного вызова SpatialPointerPose::TryGetAtTimestamp с использованием исторической метки времени, соответствующей входному событию.

Однако для входных данных, которые маршрутит через SpatialInteractionManager, существует более простой метод. SpatialInteractionSourceState имеет собственную функцию TryGetAtTimestamp. Вызов, предоставляющий идеально коррелированные пространственные точки SpatialPointerPose без догадок. Дополнительные сведения о работе с SpatialInteractionSourceStates см. в документации по DirectX по рукам и контроллерам движения .


Калибровка

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

  • Пользователь использует устройство впервые.
  • Пользователь ранее отказался от калибровки.
  • Не удалось выполнить калибровку в последний раз, когда пользователь работал с устройством.

Разработчики должны обеспечить достаточную поддержку для пользователей, где данные отслеживания взгляда могут быть недоступны. Узнайте больше о рекомендациях по резервным решениям в отслеживании взгляда на HoloLens 2.


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