Suivi oculaire étendu dans Unity

Pour accéder au dépôt GitHub pour l’exemple de suivi oculaire étendu :

Le suivi oculaire étendu est une nouvelle fonctionnalité dans HoloLens 2. Il s’agit d’un sur-ensemble du suivi oculaire standard, qui fournit uniquement des données de regard combinés. Le suivi oculaire étendu fournit également des données de regard individuels et permet aux applications de définir différentes fréquences d’images pour les données de regard, telles que 30, 60 et 90 images/s. D’autres fonctionnalités, telles que l’ouverture des yeux et la vergence des yeux, ne sont pas prises en charge par HoloLens 2 pour l’instant.

Le SDK De suivi oculaire étendu permet aux applications d’accéder aux données et aux fonctionnalités du suivi oculaire étendu. Il peut être utilisé avec les API OpenXR ou les API WinRT héritées.

Cet article décrit les façons d’utiliser le SDK de suivi oculaire étendu dans Unity avec le plug-in OpenXR Mixed Reality.

Configuration du projet

  1. Configurez le projet Unity pour le développement HoloLens.
    • Sélectionner la fonctionnalité Entrée du regard
  2. Importez le plug-in Mixed Reality OpenXR à partir de l’outil de fonctionnalité MRTK.
  3. Importez le package NuGet du Kit de développement logiciel (SDK) Eye Tracking dans votre projet Unity.
    1. Téléchargez et installez le package NuGetForUnity .
    2. Dans l’éditeur Unity, accédez à NuGet->Manage NuGet Packages, puis recherchez Microsoft.MixedReality.EyeTracking
    3. Cliquez sur le bouton Installer pour importer la dernière version du package NuGet.
      Capture d’écran du package Nuget du Kit de développement logiciel (SDK) Eye Tracking.
  4. Ajoutez les scripts d’assistance Unity.
    1. Ajoutez le ExtendedEyeGazeDataProvider.cs script à partir d’ici à votre projet Unity.
    2. Créez une scène, puis attachez le ExtendedEyeGazeDataProvider.cs script à n’importe quel GameObject.
  5. Consommez les fonctions de ExtendedEyeGazeDataProvider.cs et implémentez vos logiques.
  6. Générez et déployez sur HoloLens.

Utiliser les fonctions de ExtendedEyeGazeDataProvider

Notes

Le ExtendedEyeGazeDataProvider script dépend de certaines API du plug-in OpenXR Mixed Reality pour convertir les coordonnées des données du regard. Cela ne peut pas fonctionner si votre projet Unity utilise le plug-in XR Windows déprécié ou le XR intégré hérité dans l’ancienne version d’Unity. Pour que le suivi oculaire étendu fonctionne également dans ces scénarios :

  • Si vous avez juste besoin d’accéder aux paramètres de fréquence d’images, la Mixed Reality plug-in OpenXR n’est pas nécessaire, et vous pouvez modifier pour ExtendedEyeGazeDataProvider conserver uniquement la logique liée à la fréquence d’images.
  • Si vous avez toujours besoin d’accéder aux données individuelles du regard, vous devez utiliser les API WinRT dans Unity. Pour savoir comment utiliser le SDK de suivi oculaire étendu avec les API WinRT, reportez-vous à la section « Voir aussi ».

La ExtendedEyeGazeDataProvider classe encapsule les API du SDK de suivi oculaire étendu. Il fournit des fonctions permettant d’obtenir la lecture du regard dans l’espace du monde Unity ou par rapport à la caméra main.

Voici des exemples de code à utiliser ExtendedEyeGazeDataProvider pour obtenir les données du regard.

ExtendedEyeGazeDataProvider extendedEyeGazeDataProvider;
void Update() {
    timestamp = DateTime.Now;

    var leftGazeReadingInWorldSpace = extendedEyeGazeDataProvider.GetWorldSpaceGazeReading(extendedEyeGazeDataProvider.GazeType.Left, timestamp);
    var rightGazeReadingInWorldSpace = extendedEyeGazeDataProvider.GetWorldSpaceGazeReading(extendedEyeGazeDataProvider.GazeType.Right, timestamp);
    var combinedGazeReadingInWorldSpace = extendedEyeGazeDataProvider.GetWorldSpaceGazeReading(extendedEyeGazeDataProvider.GazeType.Combined, timestamp);

    var combinedGazeReadingInCameraSpace = extendedEyeGazeDataProvider.GetCameraSpaceGazeReading(extendedEyeGazeDataProvider.GazeType.Combined, timestamp);
}

Lorsque le ExtendedEyeGazeDataProvider script s’exécute, il définit la fréquence d’images des données du regard sur l’option la plus élevée, qui est actuellement de 90 images/s.

Référence d’API du SDK de suivi oculaire étendu

Outre l’utilisation du ExtendedEyeGazeDataProvider script, vous pouvez également créer votre propre script pour utiliser directement les API du SDK suivantes.

namespace Microsoft.MixedReality.EyeTracking
{
    /// <summary>
    /// Allow discovery of Eye Gaze Trackers connected to the system
    /// This is the only class from the Extended Eye Tracking SDK that the application will instantiate, 
    /// other classes' instances will be returned by method calls or properties.
    /// </summary>
    public class EyeGazeTrackerWatcher
    {
        /// <summary>
        /// Constructs an instance of the watcher
        /// </summary>
        public EyeGazeTrackerWatcher();

        /// <summary>
        /// Starts trackers enumeration.
        /// </summary>
        /// <returns>Task representing async action; completes when the initial enumeration is completed</returns>
        public System.Threading.Tasks.Task StartAsync();

        /// <summary>
        /// Stop listening to trackers additions and removal
        /// </summary>
        public void Stop();

        /// <summary>
        /// Raised when an Eye Gaze tracker is connected
        /// </summary>
        public event System.EventHandler<EyeGazeTracker> EyeGazeTrackerAdded;

        /// <summary>
        /// Raised when an Eye Gaze tracker is disconnected
        /// </summary>
        public event System.EventHandler<EyeGazeTracker> EyeGazeTrackerRemoved;        
    }

    /// <summary>
    /// Represents an Eye Tracker device
    /// </summary>
    public class EyeGazeTracker
    {
        /// <summary>
        /// True if Restricted mode is supported, which means the driver supports providing individual 
        /// eye gaze vector and frame rate 
        /// </summary>
        public bool IsRestrictedModeSupported;

        /// <summary>
        /// True if Vergence Distance is supported by tracker
        /// </summary>
        public bool IsVergenceDistanceSupported;

        /// <summary>
        /// True if Eye Openness is supported by the driver
        /// </summary>
        public bool IsEyeOpennessSupported;

        /// <summary>
        /// True if individual gazes are supported
        /// </summary>
        public bool AreLeftAndRightGazesSupported;

        /// <summary>
        /// Get the supported target frame rates of the tracker
        /// </summary>
        public System.Collections.Generic.IReadOnlyList<EyeGazeTrackerFrameRate> SupportedTargetFrameRates;

        /// <summary>
        /// NodeId of the tracker, used to retrieve a SpatialLocator or SpatialGraphNode to locate the tracker in the scene
        /// for the Perception API, use SpatialGraphInteropPreview.CreateLocatorForNode
        /// for the Mixed Reality OpenXR API, use SpatialGraphNode.FromDynamicNodeId
        /// </summary>
        public Guid TrackerSpaceLocatorNodeId;

        /// <summary>
        /// Opens the tracker
        /// </summary>
        /// <param name="restrictedMode">True if restricted mode active</param>
        /// <returns>Task representing async action; completes when the initial enumeration is completed</returns>
        public System.Threading.Tasks.Task OpenAsync(bool restrictedMode);

        /// <summary>
        /// Closes the tracker
        /// </summary>
        public void Close();

        /// <summary>
        /// Changes the target frame rate of the tracker
        /// </summary>
        /// <param name="newFrameRate">Target frame rate</param>
        public void SetTargetFrameRate(EyeGazeTrackerFrameRate newFrameRate);

        /// <summary>
        /// Try to get tracker state at a given timestamp
        /// </summary>
        /// <param name="timestamp">timestamp</param>
        /// <returns>State if available, null otherwise</returns>
        public EyeGazeTrackerReading TryGetReadingAtTimestamp(DateTime timestamp);

        /// <summary>
        /// Try to get tracker state at a system relative time
        /// </summary>
        /// <param name="time">time</param>
        /// <returns>State if available, null otherwise</returns>
        public EyeGazeTrackerReading TryGetReadingAtSystemRelativeTime(TimeSpan time);

        /// <summary>
        /// Try to get first first tracker state after a given timestamp
        /// </summary>
        /// <param name="timestamp">timestamp</param>
        /// <returns>State if available, null otherwise</returns>
        public EyeGazeTrackerReading TryGetReadingAfterTimestamp(DateTime timestamp);

        /// <summary>
        /// Try to get the first tracker state after a system relative time
        /// </summary>
        /// <param name="time">time</param>
        /// <returns>State if available, null otherwise</returns>
        public EyeGazeTrackerReading TryGetReadingAfterSystemRelativeTime(TimeSpan time);
    }

    /// <summary>
    /// Represents a frame rate supported by an Eye Tracker
    /// </summary>
    public class EyeGazeTrackerFrameRate
    {
        /// <summary>
        /// Frames per second of the frame rate
        /// </summary>
        public UInt32 FramesPerSecond;
    }

    /// <summary>
    /// Snapshot of Gaze Tracker state
    /// </summary>
    public class EyeGazeTrackerReading
    {
        /// <summary>
        /// Timestamp of state
        /// </summary>
        public DateTime Timestamp;

        /// <summary>
        /// Timestamp of state as system relative time
        /// Its SystemRelativeTime.Ticks could provide the QPC time to locate tracker pose 
        /// </summary>
        public TimeSpan SystemRelativeTime;

        /// <summary>
        /// Indicates of user calibration is valid
        /// </summary>
        public bool IsCalibrationValid;

        /// <summary>
        /// Tries to get a vector representing the combined gaze related to the tracker's node
        /// </summary>
        /// <param name="origin">Origin of the gaze vector</param>
        /// <param name="direction">Direction of the gaze vector</param>
        /// <returns></returns>
        public bool TryGetCombinedEyeGazeInTrackerSpace(out System.Numerics.Vector3 origin, out System.Numerics.Vector3 direction);

        /// <summary>
        /// Tries to get a vector representing the left eye gaze related to the tracker's node
        /// </summary>
        /// <param name="origin">Origin of the gaze vector</param>
        /// <param name="direction">Direction of the gaze vector</param>
        /// <returns></returns>
        public bool TryGetLeftEyeGazeInTrackerSpace(out System.Numerics.Vector3 origin, out System.Numerics.Vector3 direction);

        /// <summary>
        /// Tries to get a vector representing the right eye gaze related to the tracker's node position
        /// </summary>
        /// <param name="origin">Origin of the gaze vector</param>
        /// <param name="direction">Direction of the gaze vector</param>
        /// <returns></returns>
        public bool TryGetRightEyeGazeInTrackerSpace(out System.Numerics.Vector3 origin, out System.Numerics.Vector3 direction);

        /// <summary>
        /// Tries to read vergence distance
        /// </summary>
        /// <param name="value">Vergence distance if available</param>
        /// <returns>bool if value is valid</returns>
        public bool TryGetVergenceDistance(out float value);

        /// <summary>
        /// Tries to get left Eye openness information
        /// </summary>
        /// <param name="value">Eye Openness if valid</param>
        /// <returns>bool if value is valid</returns>
        public bool TryGetLeftEyeOpenness(out float value);

        /// <summary>
        /// Tries to get right Eye openness information
        /// </summary>
        /// <param name="value">Eye openness if valid</param>
        /// <returns>bool if value is valid</returns>
        public bool TryGetRightEyeOpenness(out float value);
    }
}

Voir aussi