Entrée du regard de la tête et du regard dans DirectX

Notes

Cet article concerne les API winRT natives héritées. Pour les nouveaux projets d’application native, nous vous recommandons d’utiliser l’API OpenXR.

Dans Windows Mixed Reality, l’entrée du regard et du regard de la tête est utilisée pour déterminer ce que l’utilisateur regarde. Vous pouvez utiliser les données pour piloter des modèles d’entrée principaux tels que le regard de la tête et la validation, et fournir un contexte pour différents types d’interaction. Il existe deux types de vecteurs de regard disponibles via l’API : le regard de la tête et le regard. Les deux sont fournis sous forme de rayon tridimensionnel avec une origine et une direction. Les applications peuvent ensuite diffuser dans leurs scènes, ou dans le monde réel, et déterminer ce que l’utilisateur cible.

Le regard de la tête représente la direction vers laquelle la tête de l’utilisateur est pointée. Considérez le regard de la tête comme la position et la direction vers l’avant de l’appareil lui-même, avec la position comme point central entre les deux écrans. Le regard de la tête est disponible sur tous les appareils Mixed Reality.

Le regard représente la direction vers laquelle les yeux de l’utilisateur regardent. L’origine se trouve entre les yeux de l’utilisateur. Il est disponible sur Mixed Reality appareils qui incluent un système de suivi oculaire.

Les rayons de la tête et du regard sont accessibles via l’API SpatialPointerPose . Appelez SpatialPointerPose::TryGetAtTimestamp pour recevoir un nouvel objet SpatialPointerPose au niveau de l’horodatage et du système de coordonnées spécifiés. Ce SpatialPointerPose contient une origine et une direction du regard de la tête. Il contient également une origine et une direction du regard si le suivi oculaire est disponible.

Prise en charge des appareils

Fonctionnalité HoloLens (1ère génération) HoloLens 2 Casques immersifs
Suivi de la tête ✔️ ✔️ ✔️
Vue d’œil ✔️

Utilisation du regard de la tête

Pour accéder au regard de la tête, commencez par appeler SpatialPointerPose::TryGetAtTimestamp pour recevoir un nouvel objet SpatialPointerPose. Transmettez les paramètres suivants.

  • SpatialCoordinateSystem qui représente le système de coordonnées souhaité pour le regard de la tête. Cela est représenté par la variable coordinateSystem dans le code suivant. Pour plus d’informations, consultez notre guide du développeur de systèmes de coordonnées .
  • Horodatage qui représente l’heure exacte de la pose de tête demandée. En règle générale, vous utiliserez un horodatage qui correspond à l’heure à laquelle l’image actuelle sera affichée. Vous pouvez obtenir ce timestamp d’affichage prédit à partir d’un objet HolographicFramePrediction , qui est accessible via l’HolographicFrame actuel. Cet objet HolographicFramePrediction est représenté par la variable de prédiction dans le code suivant.

Une fois que vous disposez d’un SpatialPointerPose valide, la position de la tête et la direction vers l’avant sont accessibles en tant que propriétés. Le code suivant montre comment y accéder.

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
}

Utilisation du regard

Pour que vos utilisateurs utilisent l’entrée du regard, chaque utilisateur doit passer par un étalonnage de l’utilisateur de suivi oculaire la première fois qu’ils utilisent l’appareil. L’API de regard est similaire au regard de la tête. Il utilise la même API SpatialPointerPose , qui fournit une origine et une direction de rayon que vous pouvez diffuser par rayons sur votre scène. La seule différence est que vous devez activer explicitement le suivi oculaire avant de l’utiliser :

  1. Demandez à l’utilisateur l’autorisation d’utiliser le suivi oculaire dans votre application.
  2. Activez la fonctionnalité « Entrée du regard » dans le manifeste de votre package.

Demande d’accès à l’entrée du regard

Lorsque votre application démarre, appelez EyesPose::RequestAccessAsync pour demander l’accès au suivi oculaire. Le système invite l’utilisateur si nécessaire et retourne GazeInputAccessStatus::Allowed une fois l’accès accordé. Il s’agit d’un appel asynchrone, ce qui nécessite un peu de gestion supplémentaire. L’exemple suivant lance un std::thread détaché pour attendre le résultat, qu’il stocke dans une variable membre appelée 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();

Le démarrage d’un thread détaché n’est qu’une option pour gérer les appels asynchrones. Vous pouvez également utiliser la nouvelle fonctionnalité co_await prise en charge par C++/WinRT. Voici un autre exemple pour demander l’autorisation utilisateur :

  • EyesPose::IsSupported() permet à l’application de déclencher la boîte de dialogue d’autorisation uniquement s’il existe un suivi oculaire.
  • GazeInputAccessStatus m_gazeInputAccessStatus; Cela permet d’éviter que l’invite d’autorisation s’affiche encore et encore.
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;	
		}
	});
}

Déclaration de la fonctionnalité d’entrée du regard

Double-cliquez sur le fichier appxmanifest dans Explorateur de solutions. Accédez ensuite à la section Fonctionnalités et case activée la fonctionnalité Entrée du regard.

Capacité d’entrée du regard

Cela ajoute les lignes suivantes à la section Package dans le fichier appxmanifest :

  <Capabilities>
    <DeviceCapability Name="gazeInput" />
  </Capabilities>

Obtenir le rayon du regard

Une fois que vous avez reçu l’accès à ET, vous êtes libre d’attraper le rayon du regard à chaque cadre. Comme avec le regard de la tête, obtenez spatialPointerPose en appelant SpatialPointerPose::TryGetAtTimestamp avec un horodatage et un système de coordonnées souhaités. SpatialPointerPose contient un objet EyesPose via la propriété Eyes . Cette valeur n’est pas null uniquement si le suivi oculaire est activé. À partir de là, vous pouvez case activée si l’utilisateur de l’appareil dispose d’un étalonnage de suivi oculaire en appelant EyesPose::IsCalibrationValid. Ensuite, utilisez la propriété Regarde pour obtenir la spatialRay contenant la position et la direction du regard. La propriété Regarde peut parfois être null. Veillez donc à case activée pour cela. Cela peut se produire si un utilisateur étalonné ferme temporairement les yeux.

Le code suivant montre comment accéder au rayon du regard.

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
		}
	}
}

Secours lorsque le suivi oculaire n’est pas disponible

Comme mentionné dans nos documents de conception sur le suivi oculaire, les concepteurs et les développeurs doivent être conscients des cas où les données de suivi oculaire peuvent ne pas être disponibles.

Il existe différentes raisons pour lesquelles les données ne sont pas disponibles :

  • Un utilisateur qui n’est pas étalonné
  • Un utilisateur a refusé à l’application l’accès à ses données de suivi oculaire
  • Des interférences temporaires, telles que des taches sur la visière HoloLens ou des cheveux obludant les yeux de l’utilisateur.

Bien que certaines api aient déjà été mentionnées dans ce document, nous fournissons un résumé de la façon de détecter que le suivi oculaire est disponible à titre de référence rapide :

Vous pouvez également case activée que vos données de suivi oculaire ne sont pas obsolètes en ajoutant un délai d’expiration entre les mises à jour des données de suivi oculaire reçues et le secours au regard de la tête, comme indiqué ci-dessous. Pour plus d’informations, consultez nos considérations relatives à la conception de secours .


Mise en corrélation du regard avec d’autres entrées

Parfois, vous pouvez constater que vous avez besoin d’un SpatialPointerPose qui correspond à un événement dans le passé. Par exemple, si l’utilisateur effectue une opération Air Tap, votre application peut vouloir savoir ce qu’il regardait. À cet effet, le simple fait d’utiliser SpatialPointerPose::TryGetAtTimestamp avec l’intervalle de temps prédit serait inexact en raison de la latence entre le traitement des entrées système et l’heure d’affichage. En outre, si vous utilisez le regard pour le ciblage, nos yeux ont tendance à se déplacer avant même de terminer une action de validation. Il s’agit moins d’un problème pour un simple air tap, mais devient plus critique lors de la combinaison de commandes vocales longues avec des mouvements oculaires rapides. Une façon de gérer ce scénario consiste à effectuer un appel supplémentaire à SpatialPointerPose::TryGetAtTimestamp, à l’aide d’un horodatage historique qui correspond à l’événement d’entrée.

Toutefois, pour les entrées qui acheminent via SpatialInteractionManager, il existe une méthode plus simple. SpatialInteractionSourceState a sa propre fonction TryGetAtTimestamp. Appel qui fournira un SpatialPointerPose parfaitement corrélé sans les suppositions. Pour plus d’informations sur l’utilisation de SpatialInteractionSourceStates, consultez la documentation Hands and Motion Controllers in DirectX .


Étalonnage

Pour que le suivi oculaire fonctionne avec précision, chaque utilisateur doit passer par un étalonnage utilisateur de suivi oculaire. Cela permet à l’appareil d’ajuster le système pour une expérience d’affichage plus confortable et de meilleure qualité pour l’utilisateur et de garantir un suivi oculaire précis en même temps. Les développeurs n’ont pas besoin de faire quoi que ce soit de leur côté pour gérer l’étalonnage des utilisateurs. Le système garantit que l’utilisateur est invité à étalonner l’appareil dans les circonstances suivantes :

  • L'utilisateur se sert de l'appareil pour la première fois.
  • L'utilisateur a précédemment refusé le processus d'étalonnage.
  • Le processus d'étalonnage n'a pas abouti la dernière fois que l'utilisateur s'est servi de l'appareil.

Les développeurs doivent veiller à fournir une prise en charge adéquate pour les utilisateurs où les données de suivi oculaire peuvent ne pas être disponibles. Pour en savoir plus sur les considérations relatives aux solutions de secours, consultez Suivi oculaire sur HoloLens 2.


Voir aussi