Entrée en regard des points de regard et de pointage dans DirectXHead-gaze and eye-gaze input in DirectX

Notes

Cet article s’applique aux API natives WinRT héritées.This article relates to the legacy WinRT native APIs. Pour les nouveaux projets d’application native, nous vous recommandons d’utiliser l' API OpenXR.For new native app projects, we recommend using the OpenXR API.

Dans Windows Mixed Reality, l’entrée en regard de l’œil et de la tête est utilisée pour déterminer ce que l’utilisateur examine.In Windows Mixed Reality, eye and head gaze input is used to determine what the user is looking at. Vous pouvez utiliser les données pour piloter des modèles d’entrée principaux tels que le point d’interposition et la validation, et fournir un contexte pour différents types d’interaction.You can use the data to drive primary input models like head-gaze and commit, and provide context for different interaction types. Deux types de vecteurs de pointage sont disponibles par le biais de l’API : le point de regard et l’œil.There are two types of gaze vectors available through the API: head-gaze and eye-gaze. Les deux sont fournis sous la forme d’un rayon tridimensionnel avec une origine et une direction.Both are provided as a three-dimensional ray with an origin and direction. Les applications peuvent ensuite raycast dans leurs scènes ou dans le monde réel, et déterminer ce que l’utilisateur cible.Applications can then raycast into their scenes, or the real world, and determine what the user is targeting.

Tête- point de regard représente la direction dans laquelle la tête de l’utilisateur est pointée.Head-gaze represents the direction that the user's head is pointed in. Pensez à la position et à la direction vers l’avant de l’appareil lui-même, la position étant le point central entre les deux affichages.Think of head-gaze as the position and forward direction of the device itself, with the position as the center point between the two displays. La tête de regard est disponible sur tous les appareils de réalité mixte.Head-gaze is available on all Mixed Reality devices.

Eye-point de regard représente la direction vers laquelle les yeux de l’utilisateur cherchent.Eye-gaze represents the direction that the user's eyes are looking towards. L’origine est située entre les yeux de l’utilisateur.The origin is located between the user's eyes. Elle est disponible sur les appareils de réalité mixte qui incluent un système de suivi oculaire.It's available on Mixed Reality devices that include an eye tracking system.

Les rayons de tête et de regard sont accessibles par le biais de l’API SpatialPointerPose .Both head and eye-gaze rays are accessible through the SpatialPointerPose API. Appelez SpatialPointerPose :: TryGetAtTimestamp pour recevoir un nouvel objet SpatialPointerPose à l’horodatage et au système de coordonnéesspécifiés.Call SpatialPointerPose::TryGetAtTimestamp to receive a new SpatialPointerPose object at the specified timestamp and coordinate system. Ce SpatialPointerPose contient une origine et une direction de pointage.This SpatialPointerPose contains a head-gaze origin and direction. Elle contient également un point d’origine et une direction de regard si le suivi oculaire est disponible.It also contains an eye-gaze origin and direction if eye tracking is available.

Prise en charge des appareilsDevice support

FonctionnalitéFeature HoloLens (1ère génération)HoloLens (1st gen) HoloLens 2HoloLens 2 Casques immersifsImmersive headsets
Suivi de la têteHead-gaze ✔️✔️ ✔️✔️ ✔️✔️
Œil-point de regardEye-gaze ✔️✔️

Utilisation de l’en-têteUsing head-gaze

Pour accéder au point de regard, commencez par appeler SpatialPointerPose :: TryGetAtTimestamp pour recevoir un nouvel objet SpatialPointerPose.To access the head-gaze, start by calling SpatialPointerPose::TryGetAtTimestamp to receive a new SpatialPointerPose object. Transmettez les paramètres suivants.Pass the following parameters.

  • SpatialCoordinateSystem qui représente le système de coordonnées souhaité pour le point de regard.A SpatialCoordinateSystem that represents the coordinate system you want for the head-gaze. Elle est représentée par la variable coordinateSystem dans le code suivant.This is represented by the coordinateSystem variable in the following code. Pour plus d’informations, consultez notre guide de développement des systèmes de coordonnées .For more information, visit our coordinate systems developer guide.
  • Horodateur qui représente l’heure exacte de la pose demandée.A Timestamp that represents the exact time of the head pose requested. En général, vous utilisez un horodatage qui correspond à l’heure à laquelle le frame actuel sera affiché.Typically, you'll use a timestamp that corresponds to the time when the current frame will be displayed. Vous pouvez obtenir cet horodateur d’affichage prédit à partir d’un objet HolographicFramePrediction , qui est accessible via le HolographicFrameactuel.You can get this predicted display timestamp from a HolographicFramePrediction object, which is accessible through the current HolographicFrame. Cet objet HolographicFramePrediction est représenté par la variable de prédiction dans le code suivant.This HolographicFramePrediction object is represented by the prediction variable in the following code.

Une fois que vous avez un SpatialPointerPose valide, la position de la tête et la direction vers l’avant sont accessibles en tant que propriétés.Once you have a valid SpatialPointerPose, the head position and forward direction are accessible as properties. Le code suivant montre comment y accéder.The following code shows how to access them.

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 des yeuxUsing eye-gaze

Pour que vos utilisateurs utilisent une entrée en regard de l’œil, chaque utilisateur doit passer par un étalonnage de l' utilisateur de suivi oculaire la première fois qu’il utilise l’appareil.For your users to use eye-gaze input, each user has to go through an eye tracking user calibration the first time they use the device. L’API Eye-regard est semblable à la tête de regard.The eye-gaze API is similar to head-gaze. Elle utilise la même API SpatialPointerPose , qui fournit une origine de rayon et une direction que vous pouvez raycast par rapport à votre scène.It uses the same SpatialPointerPose API, which provides a ray origin and direction that you can raycast against your scene. La seule différence est que vous devez activer explicitement le suivi visuel avant de l’utiliser :The only difference is that you need to explicitly enable eye tracking before using it:

  1. Demandez à l’utilisateur l’autorisation d’utiliser le suivi oculaire dans votre application.Request user permission to use eye tracking in your app.
  2. Activez la fonctionnalité « entrée de regard » dans le manifeste de votre package.Enable the "Gaze Input" capability in your package manifest.

Demande d’accès à une entrée en regard des yeuxRequesting access to eye-gaze input

Lorsque votre application démarre, appelez EyesPose :: RequestAccessAsync pour demander l’accès au suivi oculaire.When your app is starting up, call EyesPose::RequestAccessAsync to request access to eye tracking. Le système demande à l’utilisateur si nécessaire et retourne GazeInputAccessStatus :: allowed une fois que l’accès a été accordé.The system will prompt the user if needed, and return GazeInputAccessStatus::Allowed once access has been granted. Il s’agit d’un appel asynchrone, ce qui nécessite un peu de gestion supplémentaire.This is an asynchronous call, so it requires a bit of extra management. L’exemple suivant montre comment effectuer une opération de détachement d’un thread std :: thread pour attendre le résultat, qu’il stocke dans une variable membre appelée m_isEyeTrackingEnabled.The following example spins up a detached std::thread to wait for the result, which it stores to a member variable called 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.Starting a detached thread is just one option for handling async calls. Vous pouvez également utiliser les nouvelles fonctionnalités de co_await prises en charge par C++/WinRT.You could also use the new co_await functionality supported by C++/WinRT. Voici un autre exemple de demande d’autorisation de l’utilisateur :Here's another example for asking for user permission:

  • EyesPose :: IsSupported () permet à l’application de déclencher la boîte de dialogue d’autorisation uniquement s’il existe un dispositif de suivi oculaire.EyesPose::IsSupported() allows the application to trigger the permission dialog only if there's an eye tracker.
  • GazeInputAccessStatus m_gazeInputAccessStatus ; Cela permet d’éviter de relancer l’invite d’autorisation.GazeInputAccessStatus m_gazeInputAccessStatus; // This is to prevent popping up the permission prompt over and over again.
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 capacité d’entrée en regardDeclaring the Gaze Input capability

Double-cliquez sur le fichier appxmanifest dans Explorateur de solutions.Double-click the appxmanifest file in Solution Explorer. Accédez ensuite à la section fonctionnalités et vérifiez la capacité d’entrée de regard .Then navigate to the Capabilities section and check the Gaze Input capability.

Capacité d’entrée en regard

Cela ajoute les lignes suivantes à la section package dans le fichier appxmanifest :This adds the following lines to the Package section in the appxmanifest file:

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

Obtenir le regard de l’œilGetting the eye-gaze ray

Une fois que vous avez reçu l’accès à ET, vous êtes libre de prendre le regard de chaque image.Once you have received access to ET, you're free to grab the eye-gaze ray every frame. Comme avec le point de regard, récupérez SpatialPointerPose en appelant SpatialPointerPose :: TryGetAtTimestamp avec un horodatage et un système de coordonnées souhaités.As with head-gaze, get the SpatialPointerPose by calling SpatialPointerPose::TryGetAtTimestamp with a desired timestamp and coordinate system. SpatialPointerPose contient un objet EyesPose via la propriété Eyes .The SpatialPointerPose contains an EyesPose object through the Eyes property. Ce n’est pas NULL uniquement si le suivi oculaire est activé.This is non-null only if eye tracking is enabled. À partir de là, vous pouvez vérifier si l’utilisateur de l’appareil a un étalonnage de suivi oculaire en appelant EyesPose :: IsCalibrationValid.From there, you can check if the user in the device has an eye tracking calibration by calling EyesPose::IsCalibrationValid. Ensuite, utilisez la propriété de pointage pour récupérer le SpatialRay contenant la position et la direction de l’oeil.Next, use the Gaze property to get the SpatialRay containing the eye-gaze position and direction. La propriété de pointage peut parfois avoir la valeur null. Assurez-vous de le vérifier.The Gaze property can sometimes be null, so be sure to check for this. Cela peut se produire si un utilisateur calibré ferme temporairement ses yeux.This can happen is if a calibrated user temporarily closes their eyes.

L’exemple de code suivant montre comment accéder à l’œil-regard.The following code shows how to access the eye-gaze ray.

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 disponibleFallback when eye tracking isn't available

Comme mentionné dans nos documents sur la conception des suivis oculaires, les concepteurs et les développeurs doivent connaître les instances où les données de suivi oculaire peuvent ne pas être disponibles.As mentioned in our eye tracking design docs, both designers and developers should be aware of instances where eye tracking data may not be available.

Il existe plusieurs raisons pour lesquelles les données ne sont pas disponibles :There are various reasons for data being unavailable:

  • Un utilisateur n’est pas étalonnéA user not being calibrated
  • Un utilisateur a refusé l’accès de l’application à ses données de suivi oculaireA user has denied the app access to his/her eye tracking data
  • Les interférences temporaires, telles que les traînées sur le Visor HoloLens ou les cheveux, boucher les yeux de l’utilisateur.Temporary interferences, such as smudges on the HoloLens visor or hair occluding the user's eyes.

Alors que certaines API ont 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 en tant que référence rapide :While some of the APIs have already been mentioned in this document, in the following, we provide a summary of how to detect that eye tracking is available as a quick reference:

Vous pouvez également vérifier que vos données de suivi oculaire ne sont pas obsolètes en ajoutant un délai d’expiration entre les mises à jour reçues des données de suivi oculaire et en conversant le point de vue de la tête, comme indiqué ci-dessous.You may also want to check that your eye tracking data isn't stale by adding a timeout between received eye tracking data updates and otherwise fallback to head-gaze as discussed below.
Pour plus d’informations, consultez les considérations relatives à la conception de secours.Visit our fallback design considerations for more information.


Corrélation du regard avec d’autres entréesCorrelating gaze with other inputs

Il peut arriver que vous ayez besoin d’un SpatialPointerPose qui correspond à un événement dans le passé.Sometimes you may find that you need a SpatialPointerPose that corresponds with an event in the past. Par exemple, si l’utilisateur fait un robinet d’air, votre application peut souhaiter savoir ce qu’elle recherchait.For example, if the user does an Air Tap, your app might want to know what they were looking at. À cet effet, l’utilisation simple de SpatialPointerPose :: TryGetAtTimestamp avec le temps de trame prédit serait inexacte en raison de la latence entre le traitement d’entrée du système et la durée d’affichage.For this purpose, simply using SpatialPointerPose::TryGetAtTimestamp with the predicted frame time would be inaccurate because of the latency between system input processing and display time. En outre, si vous utilisez des yeux pour le ciblage, nos yeux ont tendance à se déplacer même avant de terminer une action de validation.Also, if using eye-gaze for targeting, our eyes tend to move on even before finishing a commit action. Il s’agit d’un problème moins grave pour une pression aérienne simple, mais il devient plus critique lors de la combinaison de longues commandes vocales avec des mouvements d’œil rapides.This is less of an issue for a simple Air Tap, but becomes more critical when combining long voice commands with fast eye movements. L’une des façons de gérer ce scénario consiste à effectuer un appel supplémentaire à SpatialPointerPose :: TryGetAtTimestamp, à l’aide d’un horodateur historique qui correspond à l’événement d’entrée.One way to handle this scenario is to make an additional call to SpatialPointerPose::TryGetAtTimestamp, using a historical timestamp that corresponds to the input event.

Toutefois, pour les entrées qui acheminent le SpatialInteractionManager, il existe une méthode plus simple.However, for input that routes through the SpatialInteractionManager, there's an easier method. SpatialInteractionSourceState a sa propre fonction TryGetAtTimestamp .The SpatialInteractionSourceState has its own TryGetAtTimestamp function. L’appel de qui fournira un SpatialPointerPose parfaitement corrélé sans les deviner.Calling that will provide a perfectly correlated SpatialPointerPose without the guesswork. Pour plus d’informations sur l’utilisation de SpatialInteractionSourceStates, jetez un coup d’œil aux contrôleurs mains et motion dans la documentation DirectX.For more information on working with SpatialInteractionSourceStates, take a look at the Hands and Motion Controllers in DirectX documentation.


ÉtalonnageCalibration

Pour que le suivi des yeux fonctionne correctement, chaque utilisateur doit passer par un étalonnage de l' utilisateur de suivi oculaire.For eye tracking to work accurately, each user is required to go through an eye tracking user calibration. 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 pour garantir un suivi visuel précis en même temps.This allows the device to adjust the system for a more comfortable and higher quality viewing experience for the user and to ensure accurate eye tracking at the same time. Les développeurs n’ont rien à faire à leur bout pour gérer l’étalonnage de l’utilisateur.Developers don’t need to do anything on their end to manage user calibration. Le système s’assure que l’utilisateur est invité à étalonner l’appareil dans les circonstances suivantes :The system will ensure that the user gets prompted to calibrate the device under the following circumstances:

  • L’utilisateur utilise l’appareil pour la première foisThe user is using the device for the first time
  • L’utilisateur a précédemment choisi le processus d’étalonnageThe user previously opted out of the calibration process
  • Le processus d’étalonnage n’a pas réussi la dernière fois que l’utilisateur a utilisé l’appareilThe calibration process didn't succeed the last time the user used the device

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.Developers should make sure to provide adequate support for users where eye tracking data may not be available. En savoir plus sur les considérations relatives aux solutions de secours au suivi oculaire sur HoloLens 2.Learn more about considerations for fallback solutions at Eye tracking on HoloLens 2.


Voir aussiSee also