Rozszerzone śledzenie oczu w aucie natywnym

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 ramek dla danych wzroku, takich jak 30, 60 i 90fps. Inne funkcje, takie jak otwartość oczu i wierzchołki 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 WinRT lub interfejsami API OpenXR.

W tym artykule opisano sposoby korzystania z rozszerzonego zestawu SDK śledzenia oczu w aforcie natywnym (C# lub C++/WinRT) wraz z interfejsami API WinRT.

Konfiguracja projektu

  1. Utwórz projekt lub Holographic DirectX 11 App (Universal Windows) (C++/WinRT) przy Holographic DirectX 11 App (Universal Windows) użyciu programu Visual Studio 2019 lub nowszego albo otwórz istniejący projekt holograficznego programu Visual Studio.
  2. Zaimportuj rozszerzony zestaw SDK śledzenia oczu do projektu.
    1. W programie Visual Studio Eksplorator rozwiązań kliknij prawym przyciskiem myszy projekt —> Zarządzaj pakietami NuGet...
    2. Upewnij się, że źródło pakietu w prawym górnym rogu wskazuje nuget.org: https://api.nuget.org/v3/index.json
    3. Kliknij kartę Przeglądarka, a następnie wyszukaj Microsoft.MixedReality.EyeTrackingciąg .
    4. Kliknij przycisk Zainstaluj, aby zainstalować najnowszą wersję zestawu SDK.
      Zrzut ekranu przedstawiający pakiet Nuget zestawu SDK śledzenia oczu.
  3. Ustawianie możliwości wprowadzania spojrzenia
    1. Kliknij dwukrotnie plik Package.appxmanifest w Eksplorator rozwiązań.
    2. Kliknij kartę Możliwości , a następnie zaznacz pozycję Dane wejściowe spojrzenia.
  4. Dołącz plik główny i użyj przestrzeni nazw.
    • W przypadku projektu w języku C#:
    using Microsoft.MixedReality.EyeTracking;
    
    • W przypadku projektu C++/WinRT:
    #include <winrt/Microsoft.MixedReality.EyeTracking.h>
    using namespace winrt::Microsoft::MixedReality::EyeTracking;
    
  5. Korzystaj z rozszerzonych interfejsów API zestawu SDK śledzenia oczu i zaimplementuj logikę.
  6. Kompilowanie i wdrażanie na urządzeniu HoloLens.

Omówienie kroków pobierania danych spojrzenia

Pobieranie danych wzroku za pomocą interfejsów API zestawu SDK rozszerzonego śledzenia oczu wymaga następujących kroków:

  1. Uzyskaj dostęp do funkcji śledzenia oczu od użytkownika.
  2. Obserwuj połączenia monitora wzroku i rozłączenia.
  3. Otwórz monitor wzroku, a następnie wykonaj zapytanie o jego możliwości.
  4. Wielokrotnie odczytywane dane spojrzenia z monitora wzroku.
  5. Transferowanie danych spojrzenia do innych systemów SpatialCoordinateSystems.

Uzyskiwanie dostępu do funkcji śledzenia oczu

Aby móc używać wszelkich informacji związanych z oczami, aplikacja musi najpierw zażądać zgody użytkownika.

var status = await Windows.Perception.People.EyesPose.RequestAccessAsync();
bool useGaze = (status == Windows.UI.Input.GazeInputAccessStatus.Allowed);
auto accessStatus = co_await winrt::Windows::Perception::People::EyesPose::RequestAccessAsync();
bool useGaze = (accessStatus.get() == winrt::Windows::UI::Input::GazeInputAccessStatus::Allowed);

Wykrywanie monitora wzroku

Wykrywanie monitora EyeGazeTrackerWatcher wzroku odbywa się za pomocą klasy . EyeGazeTrackerAdded i EyeGazeTrackerRemoved zdarzenia są odpowiednio podniesione po wykryciu lub rozłączeniu monitora wzroku.

Obserwator musi być jawnie uruchomiony z StartAsync() metodą, która kończy się asynchronicznie, gdy monitory, które są już połączone, zostały zasygnalizowane za pośrednictwem EyeGazeTrackerAdded zdarzenia.

Po wykryciu EyeGazeTracker monitora wzroku wystąpienie jest przekazywane do aplikacji w EyeGazeTrackerAdded parametrach zdarzenia. W przypadku rozłączenia monitora odpowiednie EyeGazeTracker wystąpienie jest przekazywane do zdarzenia EyeGazeTrackerRemoved.

EyeGazeTrackerWatcher watcher = new EyeGazeTrackerWatcher();
watcher.EyeGazeTrackerAdded += _watcher_EyeGazeTrackerAdded;
watcher.EyeGazeTrackerRemoved += _watcher_EyeGazeTrackerRemoved;
await watcher.StartAsync();
...

private async void _watcher_EyeGazeTrackerAdded(object sender, EyeGazeTracker e)
{
    // Implementation is in next section
}

private void _watcher_EyeGazeTrackerRemoved(object sender, EyeGazeTracker e)
{
    ...
}
EyeGazeTrackerWatcher watcher;
watcher.EyeGazeTrackerAdded(std::bind(&SampleEyeTrackingNugetClientAppMain::OnEyeGazeTrackerAdded, this, _1, _2));
watcher.EyeGazeTrackerRemoved(std::bind(&SampleEyeTrackingNugetClientAppMain::OnEyeGazeTrackerRemoved, this, _1, _2));
co_await watcher.StartAsync();
...

winrt::Windows::Foundation::IAsyncAction SampleAppMain::OnEyeGazeTrackerAdded(const EyeGazeTrackerWatcher& sender, const EyeGazeTracker& tracker)
{
    // Implementation is in next section
}
void SampleAppMain::OnEyeGazeTrackerRemoved(const EyeGazeTrackerWatcher& sender, const EyeGazeTracker& tracker)
{
    ...
}

Otwórz monitor wzroku

Podczas odbierania EyeGazeTracker wystąpienia aplikacja musi najpierw ją otworzyć, wywołując metodę OpenAsync() . W razie potrzeby może ona wysyłać zapytania dotyczące możliwości trackera. Metoda OpenAsync() przyjmuje parametr logiczny. Wskazuje to, czy aplikacja musi uzyskiwać dostęp do funkcji, które nie należą do standardowego śledzenia oczu, takich jak wektory wzroku indywidualnego lub zmiana szybkości klatek monitora.

Połączone spojrzenie jest obowiązkową funkcją obsługiwaną przez wszystkie trackery wzroku. Inne funkcje, takie jak dostęp do indywidualnego spojrzenia, są opcjonalne i mogą być obsługiwane lub nie w zależności od trackera i jego sterownika. W przypadku tych opcjonalnych funkcji EyeGazeTracker klasa uwidacznia właściwość wskazującą, czy funkcja jest obsługiwana — na przykład właściwość, która wskazuje, AreLeftAndRightGazesSupported czy poszczególne informacje o spojrzeniu oka są obsługiwane przez urządzenie.

Wszystkie informacje przestrzenne uwidocznione przez śledzenie oczu są publikowane związane z samym trackerem, który jest identyfikowany przez identyfikator dynamicznego węzła. Użycie identyfikatora nodeId do uzyskania za SpatialCoordinateSystem pomocą interfejsów API WinRT może przekształcić współrzędne danych wzroku w inny system współrzędnych.

private async void _watcher_EyeGazeTrackerAdded(object sender, EyeGazeTracker e)
{
    try
    {
        // Try to open the tracker with access to restricted features
        await e.OpenAsync(true);

        // If it has succeeded, store it for future use
        _tracker = e;

        // Check support for individual eye gaze
        bool supportsIndividualEyeGaze = _tracker.AreLeftAndRightGazesSupported;

        // Get a spatial locator for the tracker, this will be used to transfer the gaze data to other coordinate systems later
        var trackerNodeId = e.TrackerSpaceLocatorNodeId;
        _trackerLocator = Windows.Perception.Spatial.Preview.SpatialGraphInteropPreview.CreateLocatorForNode(trackerNodeId);
    }
    catch (Exception ex)
    {
        // Unable to open the tracker
    }
}
winrt::Windows::Foundation::IAsyncAction SampleEyeTrackingNugetClientAppMain::OnEyeGazeTrackerAdded(const EyeGazeTrackerWatcher&, const EyeGazeTracker& tracker)
{
   auto newTracker = tracker;

   try
   {
        // Try to open the tracker with access to restricted features
        co_await newTracker.OpenAsync(true);

        // If it has succeeded, store it for future use
        m_gazeTracker = newTracker;

        // Check support for individual eye gaze
        const bool supportsIndividualEyeGaze = m_gazeTracker.AreLeftAndRightGazesSupported();

        // Get a spatial locator for the tracker. This will be used to transfer the gaze data to other coordinate systems later
        const auto trackerNodeId = m_gazeTracker.TrackerSpaceLocatorNodeId();
        m_trackerLocator = winrt::Windows::Perception::Spatial::Preview::SpatialGraphInteropPreview::CreateLocatorForNode(trackerNodeId);
   }
   catch (const winrt::hresult_error& e)
   {
       // Unable to open the tracker
   }
}

Ustawianie szybkości ramki monitora wzroku

Właściwość EyeGazeTracker.SupportedTargetFrameRates zwraca listę docelowej szybkości klatek obsługiwanych przez tracker. HoloLens 2 obsługuje 30, 60 i 90fps.

Użyj metody , EyeGazeTracker.SetTargetFrameRate() aby ustawić docelową szybkość ramki.

// This returns a list of supported frame rate: 30, 60, 90 fps in order
var supportedFrameRates = _tracker.SupportedTargetFrameRates;

// Sets the tracker at the highest supported frame rate (90 fps)
var newFrameRate = supportedFrameRates[supportedFrameRates.Count - 1];
_tracker.SetTargetFrameRate(newFrameRate);
uint newFramesPerSecond = newFrameRate.FramesPerSecond;
// This returns a list of supported frame rate: 30, 60, 90 fps in order
const auto supportedFrameRates = m_gazeTracker.SupportedTargetFrameRates();

// Sets the tracker at the highest supported frame rate (90 fps)
const auto newFrameRate = supportedFrameRates.GetAt(supportedFrameRates.Size() - 1);
m_gazeTracker.SetTargetFrameRate(newFrameRate);
const uint32_t newFramesPerSecond = newFrameRate.FramesPerSecond();

Odczytywanie danych spojrzenia z monitora wzroku

Monitor wzroku okresowo publikuje swoje stany w buforze okrągłym. Dzięki temu aplikacja odczytuje stan trackera w czasie należącym do niewielkiego przedziału czasu. Umożliwia to na przykład pobranie najnowszego stanu trackera lub jego stanu w momencie wystąpienia zdarzenia, takiego jak gest dłoni od użytkownika.

Metody pobierające stan trackera jako EyeGazeTrackerReading wystąpienie:

  • Metody TryGetReadingAtTimestamp() i TryGetReadingAtSystemRelativeTime() zwracają EyeGazeTrackerReading najbliżej czasu przekazanego przez aplikację. Śledzenie kontroluje harmonogram publikowania, więc zwrócony odczyt może być nieco starszy lub nowszy niż czas żądania. Właściwości EyeGazeTrackerReading.Timestamp i EyeGazeTrackerReading.SystemRelativeTime umożliwiają aplikacji poznanie dokładnego czasu opublikowanego stanu.

  • Metody TryGetReadingAfterTimestamp() i TryGetReadingAfterSystemRelativeTime() zwracają pierwszy EyeGazeTrackerReading ze znacznikiem czasu ściśle lepszym od czasu, który minął jako parametr. Dzięki temu aplikacja może sekwencyjnie odczytywać wszystkie stany opublikowane przez tracker. Należy pamiętać, że wszystkie te metody wysyłają zapytania do istniejącego buforu i że są zwracane natychmiast. Jeśli żaden stan nie jest dostępny, zwróci wartość null (innymi słowy, aplikacja nie będzie czekać na opublikowanie stanu).

Oprócz sygnatury EyeGazeTrackerReading czasowej wystąpienie ma IsCalibrationValid właściwość, która wskazuje, czy kalibracja monitora oczu jest prawidłowa, czy nie.

Na koniec dane przeglądania można pobrać za pomocą zestawu metod, takich jak TryGetCombinedEyeGazeInTrackerSpace() lub TryGetLeftEyeGazeInTrackerSpace(). Wszystkie te metody zwracają wartość logiczną wskazującą powodzenie. Niepowodzenie pobierania niektórych danych może oznaczać, że dane nie są obsługiwane (EyeGazeTracker ma właściwości do wykrycia tego przypadku) lub że tracker nie może pobrać danych (na przykład nieprawidłowej kalibracji lub ukrytego oka).

Jeśli na przykład aplikacja chce wyświetlić kursor odpowiadający połączonemu spojrzeniu, może wykonać zapytanie dotyczące trackera przy użyciu sygnatury czasowej przewidywania przygotowanej ramki w następujący sposób.

var holographicFrame = holographicSpace.CreateNextFrame();
var prediction = holographicFrame.CurrentPrediction;
var predictionTimestamp = prediction.Timestamp;
var reading = _tracker.TryGetReadingAtTimestamp(predictionTimestamp.TargetTime.DateTime);
if (reading != null)
{
    // Vector3 needs the System.Numerics namespace
    if (reading.TryGetCombinedEyeGazeInTrackerSpace(out Vector3 gazeOrigin, out Vector3 gazeDirection))
    {
        // Use gazeOrigin and gazeDirection to display the cursor
    }
}
auto holographicFrame = m_holographicSpace.CreateNextFrame();
auto prediction = holographicFrame.CurrentPrediction();
auto predictionTimestamp = prediction.Timestamp();
const auto reading = m_gazeTracker.TryGetReadingAtTimestamp(predictionTimestamp.TargetTime());
if (reading)
{
    float3 gazeOrigin;
    float3 gazeDirection;
    if (reading.TryGetCombinedEyeGazeInTrackerSpace(gazeOrigin, gazeDirection))
    {
        // Use gazeOrigin and gazeDirection to display the cursor
    }
}

Przekształcanie danych widoku do innego elementu SpatialCoordinateSystem

Interfejsy API WinRT zwracające dane przestrzenne, takie jak pozycja, zawsze wymagają zarówno wartości a, jak PerceptionTimestamp i SpatialCoordinateSystem. Aby na przykład pobrać połączone spojrzenie HoloLens 2 przy użyciu interfejsu API WinRT, interfejs API SpatialPointerPose.TryGetAtTimestamp() wymaga dwóch parametrów: a SpatialCoordinateSystem i PerceptionTimestamp. Gdy połączone spojrzenie jest następnie dostępne przez SpatialPointerPose.Eyes.Gaze, jego początek i kierunek są wyrażone w przekazanym SpatialCoordinateSystem .

Rozszerzone interfejsy API zestawu SDK śledzenia tye nie muszą przyjmować elementu SpatialCoordinateSystem , a dane spojrzenia są zawsze wyrażane w układzie współrzędnych trackera. Można jednak przekształcić te dane wzroku w inny układ współrzędny ze stanem monitora powiązanego z innym układem współrzędnych.

  • Jak wspomniano w powyższej sekcji "Open eye gaze tracker", aby uzyskać SpatialLocator dla trackera wzroku, wywołaj z Windows.Perception.Spatial.Preview.SpatialGraphInteropPreview.CreateLocatorForNode() właściwością EyeGazeTracker.TrackerSpaceLocatorNodeId .

  • Źródła spojrzenia i wskazówki pobierane przez EyeGazeTrackerReading są związane z trackerem wzroku.

  • SpatialLocator.TryLocateAtTimestamp() zwraca pełną lokalizację 6DoF monitora wzroku w danym miejscu PerceptionTimeStamp i powiązaną z danym SpatialCoordinateSystemelementem , którego można użyć do skonstruowania macierzy transformacji Macierz4x4.

  • Użyj macierzy przekształcania Macierz4x4 skonstruowanej w celu przeniesienia źródeł i wskazówek spojrzenia do innego systemu SpatialCoordinateSystem.

Poniższe przykłady kodu pokazują, jak obliczyć położenie modułu znajdującego się w kierunku połączonego spojrzenia, dwa mierniki przed źródłem spojrzenia;

var predictionTimestamp = prediction.Timestamp;
var stationaryCS = stationaryReferenceFrame.CoordinateSystem;
var trackerLocation = _trackerLocator.TryLocateAtTimestamp(predictionTimestamp, stationaryCS);
if (trackerLocation != null)
{
    var trackerToStationaryMatrix = Matrix4x4.CreateFromQuaternion(trackerLocation.Orientation) * Matrix4x4.CreateTranslation(trackerLocation.Position);
    var reading = _tracker.TryGetReadingAtTimestamp(predictionTimestamp.TargetTime.DateTime);
    if (reading != null)
    {
        if (reading.TryGetCombinedEyeGazeInTrackerSpace(out Vector3 gazeOriginInTrackerSpace, out Vector3 gazeDirectionInTrackerSpace))
        {
            var cubePositionInTrackerSpace = gazeOriginInTrackerSpace + 2.0f * gazeDirectionInTrackerSpace;
            var cubePositionInStationaryCS = Vector3.Transform(cubePositionInTrackerSpace, trackerToStationaryMatrix);
        }
    }
}
auto predictionTimestamp = prediction.Timestamp();
auto stationaryCS = m_stationaryReferenceFrame.CoordinateSystem();
auto trackerLocation = m_trackerLocator.TryLocateAtTimestamp(predictionTimestamp, stationaryCS);
if (trackerLocation) 
{
    auto trackerOrientation = trackerLocation.Orientation();
    auto trackerPosition = trackerLocation.Position();
    auto trackerToStationaryMatrix = DirectX::XMMatrixRotationQuaternion(DirectX::XMLoadFloat4(reinterpret_cast<const DirectX::XMFLOAT4*>(&trackerOrientation))) * DirectX::XMMatrixTranslationFromVector(DirectX::XMLoadFloat3(&trackerPosition));

    const auto reading = m_gazeTracker.TryGetReadingAtTimestamp(predictionTimestamp.TargetTime());
    if (reading)
    {
        float3 gazeOriginInTrackerSpace;
        float3 gazeDirectionInTrackerSpace;
        if (reading.TryGetCombinedEyeGazeInTrackerSpace(gazeOriginInTrackerSpace, gazeDirectionInTrackerSpace))
        {
            auto cubePositionInTrackerSpace = gazeOriginInTrackerSpace + 2.0f * gazeDirectionInTrackerSpace;
            float3 cubePositionInStationaryCS;
            DirectX::XMStoreFloat3(&cubePositionInStationaryCS, DirectX::XMVector3TransformCoord(DirectX::XMLoadFloat3(&cubePositionInTrackerSpace), trackerToStationaryMatrix));
        }
    }
}

Dokumentacja interfejsu API rozszerzonego zestawu SDK śledzenia oczu

namespace Microsoft.MixedReality.EyeTracking
{
    /// <summary>
    /// Allow discovery of Eye Gaze Trackers connected to the system
    /// This is the only class from 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 to provide individual 
        /// eye gaze vector and framerate 
        /// </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 Perception API, use SpatialGraphInteropPreview.CreateLocatorForNode
        /// for 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 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ż