Entrée de regard et de regard dans DirectX

Notes

Cet article concerne les API natives WinRT 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 de regard et de tête est utilisée pour déterminer ce que l’utilisateur examine. Vous pouvez utiliser les données pour générer des modèles d’entrée principaux tels que le regard principal 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 : regard de tête et regard. Les deux sont fournis sous la forme d’un rayon à trois dimensions avec une origine et une direction. Les applications peuvent ensuite raycast dans leurs scènes, ou le monde réel, et déterminer ce que l’utilisateur cible.

Le regard de tête représente la direction dans laquelle la tête de l’utilisateur est pointée. Considérez le regard de 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 affichages. Le regard de tête est disponible sur tous les appareils Mixed Reality.

Le regard représente la direction vers laquelle l’utilisateur cherche. 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 tête et de regard sont accessibles via l’API SpatialPointerPose . Appelez SpatialPointerPose::TryGetAtTimestamp pour recevoir un nouvel objet SpatialPointerPose à l’horodatage et au système de coordonnées spécifiés. Ce SpatialPointerPose contient une origine et une direction de regard de tête. Il contient également une origine oculaire et une direction 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 ✔️ ✔️ ✔️
Regard de regard ✔️

Utilisation du regard de tête

Pour accéder au regard principal, 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 principal. Il s’agit de la variable coordinateSystem dans le code suivant. Pour plus d’informations, consultez notre guide de développement des 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 allez utiliser un horodatage qui correspond à l’heure à laquelle l’image actuelle s’affiche. Vous pouvez obtenir cet horodatage d’affichage prédit à partir d’un objet HolographicFramePrediction , accessible par le biais de l’HolographicFrame actuel. Cet objet HolographicFramePrediction est représenté par la variable de prédiction dans le code suivant.

Une fois que vous avez un SpatialPointerPose valide, la position de tête et la direction 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 de regard, chaque utilisateur doit passer par un étalonnage de l’utilisateur de suivi oculaire la première fois qu’il utilise l’appareil. L’API de regard est similaire à celle du regard. Il utilise la même API SpatialPointerPose , qui fournit une origine et une direction de rayons que vous pouvez raycast 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 d’utiliser le suivi oculaire dans votre application.
  2. Activez la fonctionnalité « Entrée de regard » dans votre manifeste de package.

Demande d’accès à l’entrée de 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::Autorisé 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 fait tourner 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 de l’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; Il s’agit d’empêcher le basculement de l’invite d’autorisation.
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 de regard

Double-cliquez sur le fichier appxmanifest dans Explorateur de solutions. Accédez ensuite à la section Fonctionnalités et vérifiez la fonctionnalité d’entrée de regard .

Capacité d’entrée de regard

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

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

Obtention du rayon de regard

Une fois que vous avez reçu l’accès à ET, vous êtes libre de saisir le rayon de regard chaque cadre. Comme avec le regard principal, 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 . Cela n’est pas null uniquement si le suivi oculaire est activé. À partir de là, vous pouvez vérifier si l’utilisateur de l’appareil a un étalonnage de suivi oculaire en appelant EyesPose::IsCalibrationValid. Ensuite, utilisez la propriété Gaze pour obtenir le SpatialRay contenant la position et la direction du regard. La propriété de regard peut parfois être null. Veillez donc à vérifier cela. Cela peut se produire si un utilisateur étalonné ferme temporairement ses yeux.

Le code suivant montre comment accéder au rayon de 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 de suivi oculaire, les concepteurs et les développeurs doivent être conscients des instances 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 n’étant pas étalonné
  • Un utilisateur a refusé l’accès de l’application à ses données de suivi oculaire
  • Interférences temporaires, telles que des taches sur la visière HoloLens ou les cheveux occludant les yeux de l’utilisateur.

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

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


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 touche Air Tap, votre application peut vouloir savoir ce qu’il examinait. À cet effet, l’utilisation de SpatialPointerPose::TryGetAtTimestamp avec l’heure d’intervalle prédite serait inexacte en raison de la latence entre le traitement d’entrée système et l’heure d’affichage. En outre, si vous utilisez le regard pour cibler, 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 effectuent des itinéraires via SpatialInteractionManager, il existe une méthode plus facile. SpatialInteractionSourceState a sa propre fonction TryGetAtTimestamp. L’appel qui fournira un SpatialPointerPose parfaitement corrélé sans les estimations. Pour plus d’informations sur l’utilisation de SpatialInteractionSourceStates, consultez la documentation Mains et contrôleurs de mouvement dans DirectX .


Étalonnage

Pour que le suivi oculaire fonctionne correctement, chaque utilisateur doit passer par un étalonnage de l’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 rien à faire 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 s’assurer de fournir une prise en charge adéquate pour les utilisateurs où les données de suivi oculaire peuvent ne pas être disponibles. Apprenez-en davantage sur les considérations relatives aux solutions de secours au suivi oculaire sur HoloLens 2.


Voir aussi