Rozszerzone śledzenie oczu w a unity

Aby uzyskać dostęp do repozytorium GitHub dla rozszerzonego przykładu śledzenia oczu:

Rozszerzone śledzenie oczu to nowa funkcja w HoloLens 2. Jest to nadzbiór standardowego śledzenia oczu, który zapewnia tylko połączone dane wzroku. Rozszerzone śledzenie oczu zapewnia również indywidualne dane wzroku i umożliwia aplikacjom ustawianie różnych szybkości klatek dla danych spojrzenia, takich jak 30, 60 i 90fps. Inne funkcje, takie jak otwartość oczu i vergence oczu, nie są obecnie obsługiwane przez HoloLens 2.

Zestaw SDK rozszerzonego śledzenia oczu umożliwia aplikacjom dostęp do danych i funkcji rozszerzonego śledzenia oczu. Można go używać razem z interfejsami API OpenXR lub starszymi interfejsami API WinRT.

W tym artykule opisano sposoby korzystania z rozszerzonego zestawu SDK śledzenia oczu w apletu Unity wraz z wtyczką Mixed Reality OpenXR.

Konfiguracja projektu

  1. Skonfiguruj projekt aparatu Unity na potrzeby opracowywania urządzenia HoloLens.
    • Wybieranie możliwości wprowadzania danych wejściowych w portalu Gaze
  2. Zaimportuj wtyczkę Mixed Reality OpenXR z narzędzia funkcji MRTK.
  3. Zaimportuj pakiet NuGet zestawu SDK śledzenia oczu do projektu aparatu Unity.
    1. Pobierz i zainstaluj pakiet NuGetForUnity .
    2. W edytorze aparatu Unity przejdź do NuGetpozycji ->Manage NuGet Packages, a następnie wyszukaj ciąg Microsoft.MixedReality.EyeTracking
    3. Kliknij przycisk Zainstaluj, aby zaimportować najnowszą wersję pakietu NuGet.
      Zrzut ekranu przedstawiający pakiet Nuget zestawu Sdk śledzenia oczu.
  4. Dodaj skrypty pomocnika aparatu Unity.
    1. ExtendedEyeGazeDataProvider.cs Dodaj skrypt z tego miejsca do projektu aparatu Unity.
    2. Utwórz scenę, a następnie dołącz ExtendedEyeGazeDataProvider.cs skrypt do dowolnego obiektu GameObject.
  5. Korzystanie z ExtendedEyeGazeDataProvider.cs funkcji i implementowanie logiki.
  6. Kompilowanie i wdrażanie na urządzeniu HoloLens.

Korzystanie z funkcji ExtendedEyeGazeDataProvider

Uwaga

Skrypt ExtendedEyeGazeDataProvider zależy od niektórych interfejsów API z Mixed Reality wtyczki OpenXR w celu przekonwertowania współrzędnych danych spojrzenia. Nie może działać, jeśli projekt aparatu Unity używa przestarzałej wtyczki XR systemu Windows lub starszej wbudowanej wersji środowiska XR w starszej wersji aparatu Unity. Aby rozszerzone śledzenie oczu działało również w tych scenariuszach:

  • Jeśli potrzebujesz tylko dostępu do ustawień szybkości klatek, wtyczka Mixed Reality OpenXR nie jest konieczna i można zmodyfikować parametr , ExtendedEyeGazeDataProvider aby zachować tylko logikę związaną z szybkością klatek.
  • Jeśli nadal musisz uzyskać dostęp do poszczególnych danych wzroku, musisz użyć interfejsów API WinRT w akwenie Unity. Aby dowiedzieć się, jak używać rozszerzonego zestawu SDK śledzenia oczu z interfejsami API WinRT, zapoznaj się z sekcją "Zobacz również".

Klasa ExtendedEyeGazeDataProvider opakowuje rozszerzone interfejsy API zestawu SDK śledzenia oczu. Zapewnia funkcje umożliwiające odczytywanie wzroku w przestrzeni świata aparatu Unity lub względem głównego aparatu.

Poniżej przedstawiono przykłady kodu używane w ExtendedEyeGazeDataProvider celu pobrania danych spojrzenia.

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

Po wykonaniu skryptu ExtendedEyeGazeDataProvider ustawia częstotliwość ramki danych spojrzenia na najwyższą opcję, która jest obecnie 90fps.

Dokumentacja interfejsu API rozszerzonego zestawu SDK śledzenia oczu

Oprócz używania skryptu ExtendedEyeGazeDataProvider możesz również utworzyć własny skrypt, aby bezpośrednio korzystać z interfejsów API zestawu SDK.

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

Zobacz też