Erweiterte Augenverfolgung in Unity

So greifen Sie auf das GitHub-Repository für das erweiterte Eye Tracking-Beispiel zu:

Erweiterte Augenverfolgung ist eine neue Funktion in HoloLens 2. Es handelt sich um eine Übermenge der Standard-Augenverfolgung, die nur kombinierte Augensichtdaten bereitstellt. Die erweiterte Augenverfolgung bietet auch individuelle Augenaugendaten und ermöglicht es Anwendungen, unterschiedliche Bildraten für die Blickdaten festzulegen, z. B. 30, 60 und 90 fps. Andere Features wie Augenoffenheit und Augenvergänglichkeit werden von HoloLens 2 derzeit nicht unterstützt.

Das Extended Eye Tracking SDK ermöglicht Anwendungen den Zugriff auf Daten und Features des erweiterten Eye Tracking. Sie kann zusammen mit OpenXR-APIs oder älteren WinRT-APIs verwendet werden.

In diesem Artikel wird beschrieben, wie Sie das erweiterte Eye Tracking SDK in Unity zusammen mit dem Mixed Reality OpenXR-Plug-In verwenden können.

Projekteinrichtung

  1. Richten Sie das Unity-Projekt für die HoloLens-Entwicklung ein.
    • Auswählen der Funktion "Gaze Input"
  2. Importieren Sie das Mixed Reality OpenXR-Plug-In aus dem MRTK-Featuretool.
  3. Importieren Sie das NuGet-Paket des Eye Tracking SDK in Ihr Unity-Projekt.
    1. Laden Sie das NuGetForUnity-Paket herunter, und installieren Sie es.
    2. Navigieren Sie im Unity-Editor zu NuGet->Manage NuGet Packages und suchen Sie dann nach Microsoft.MixedReality.EyeTracking
    3. Klicken Sie auf die Schaltfläche Installieren, um die neueste Version des NuGet-Pakets zu importieren.
      Screenshot des Nuget-Pakets des Eye Tracking SDK
  4. Fügen Sie die Unity-Hilfsskripts hinzu.
    1. Fügen Sie das ExtendedEyeGazeDataProvider.cs Skript von hier zu Ihrem Unity-Projekt hinzu.
    2. Erstellen Sie eine Szene, und fügen Sie das ExtendedEyeGazeDataProvider.cs Skript dann an ein beliebiges GameObject an.
  5. Nutzen Sie die Funktionen von ExtendedEyeGazeDataProvider.cs und implementieren Sie Ihre Logiken.
  6. Erstellen und Bereitstellen in HoloLens.

Nutzen von Funktionen von ExtendedEyeGazeDataProvider

Hinweis

Das ExtendedEyeGazeDataProvider Skript hängt von einigen APIs aus dem Mixed Reality OpenXR-Plug-In ab, um die Koordinaten der Blickdaten zu konvertieren. Dies kann nicht funktionieren, wenn Ihr Unity-Projekt das veraltete Windows XR-Plug-In oder die ältere integrierte XR-Version in älteren Unity-Versionen verwendet. So funktioniert die erweiterte Eye-Tracking-Überwachung auch in diesen Szenarien:

  • Wenn Sie nur auf die Einstellungen für die Bildfrequenz zugreifen müssen, ist das Mixed Reality OpenXR-Plug-In nicht erforderlich, und Sie können das ExtendedEyeGazeDataProvider ändern, um nur die Logik für die Bildfrequenz beizubehalten.
  • Wenn Sie weiterhin auf einzelne Blickdaten zugreifen müssen, müssen Sie WinRT-APIs in Unity verwenden. Informationen zur Verwendung des erweiterten Eye Tracking SDK mit WinRT-APIs finden Sie im Abschnitt "Siehe auch".

Die ExtendedEyeGazeDataProvider -Klasse umschließt die erweiterten EYE TRACKING SDK-APIs. Es bietet Funktionen zum Lesen von Blicken im Unity-Weltraum oder relativ zur Standard Kamera.

Im Folgenden finden Sie Codebeispiele, die zum Abrufen der Blickdaten verwendet werden ExtendedEyeGazeDataProvider sollen.

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

Wenn das ExtendedEyeGazeDataProvider Skript ausgeführt wird, wird die Framerate der Blickdaten auf die höchste Option festgelegt, die derzeit 90fps beträgt.

API-Referenz des erweiterten Eye Tracking SDK

Abgesehen von der Verwendung des ExtendedEyeGazeDataProvider Skripts können Sie auch Ein eigenes Skript erstellen, um die folgenden SDK-APIs direkt zu nutzen.

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

Weitere Informationen