Tracciamento oculare esteso nel motore nativo

Il tracciamento oculare esteso è una nuova funzionalità in HoloLens 2. Si tratta di un superset del tracciamento oculare standard, che fornisce solo dati combinati dello sguardo fisso. Il tracciamento oculare esteso fornisce anche dati singoli dello sguardo fisso e consente alle applicazioni di impostare diverse framerate per i dati dello sguardo fisso, ad esempio 30, 60 e 90fps. Altre caratteristiche come l'apertura oculare e la vergenza oculare non sono supportate da HoloLens 2 in questo momento.

Extended Eye Tracking SDK consente alle applicazioni di accedere a dati e funzionalità di tracciamento oculare esteso. Può essere usato insieme alle API WinRT o alle API OpenXR.

Questo articolo illustra i modi per usare l'SDK di tracciamento oculare esteso nel motore nativo (C# o C++/WinRT), insieme alle API WinRT.

Configurazione del progetto

  1. Creare un Holographic DirectX 11 App (Universal Windows) progetto o Holographic DirectX 11 App (Universal Windows) (C++/WinRT) con Visual Studio 2019 o versione successiva oppure aprire il progetto di Visual Studio olografico esistente.
  2. Importare l'SDK di tracciamento oculare esteso nel progetto.
    1. Nel Esplora soluzioni di Visual Studio fare clic con il pulsante destro del mouse sul progetto -> Gestisci pacchetti NuGet...
    2. Assicurarsi che l'origine pacchetto nell'angolo superiore destro punti a nuget.org: https://api.nuget.org/v3/index.json
    3. Fare clic sulla scheda Browser e quindi cercare Microsoft.MixedReality.EyeTracking.
    4. Fare clic sul pulsante Installa per installare la versione più recente dell'SDK.
      Screenshot del pacchetto NuGet Eye Tracking SDK.
  3. Impostare la funzionalità di input sguardo fisso
    1. Fare doppio clic sul file Package.appxmanifest in Esplora soluzioni.
    2. Fare clic sulla scheda Funzionalità e quindi selezionare l'input sguardo fisso.
  4. Includere il file head e usare lo spazio dei nomi.
    • Per un progetto C#:
    using Microsoft.MixedReality.EyeTracking;
    
    • Per un progetto C++/WinRT:
    #include <winrt/Microsoft.MixedReality.EyeTracking.h>
    using namespace winrt::Microsoft::MixedReality::EyeTracking;
    
  5. Usare le API sdk di tracciamento oculare esteso e implementare la logica.
  6. Compilare e distribuire in HoloLens.

Panoramica dei passaggi per ottenere i dati dello sguardo fisso

Per ottenere i dati dello sguardo fisso tramite le API Extended Eye Tracking SDK, sono necessari i passaggi seguenti:

  1. Ottenere l'accesso alle funzionalità di tracciamento oculare dall'utente.
  2. Guarda le connessioni e le disconnessioni dello sguardo fisso.
  3. Aprire il tracker dello sguardo fisso e quindi eseguire una query sulle relative funzionalità.
  4. Legge ripetutamente i dati dello sguardo fisso dal tracker dello sguardo fisso.
  5. Trasferire i dati dello sguardo fisso ad altri spatialCoordinateSystems.

Ottenere l'accesso alle funzionalità di tracciamento oculare

Per usare qualsiasi informazione correlata agli occhi, l'applicazione deve prima richiedere il consenso dell'utente.

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

Rilevare lo sguardo fisso

Il rilevamento dello sguardo fisso viene eseguito tramite l'uso della EyeGazeTrackerWatcher classe . EyeGazeTrackerAdded gli eventi e EyeGazeTrackerRemoved vengono generati rispettivamente quando viene rilevato o disconnesso uno sguardo fisso.

Il watcher deve essere avviato in modo esplicito con il StartAsync() metodo , che viene completato in modo asincrono quando i tracker già connessi sono stati segnalato tramite l'evento EyeGazeTrackerAdded .

Quando viene rilevato uno sguardo fisso, EyeGazeTracker un'istanza viene passata all'applicazione nei parametri dell'evento EyeGazeTrackerAdded ; reciprocamente, quando un tracker viene disconnesso, l'istanza corrispondente EyeGazeTracker viene passata all'evento 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)
{
    ...
}

Tracciamento sguardo fisso aperto

Quando si riceve un'istanza EyeGazeTracker , l'applicazione deve prima aprirla chiamando il OpenAsync() metodo . Può quindi eseguire una query per le funzionalità di rilevamento, se necessario. Il OpenAsync() metodo accetta un parametro booleano, che indica se l'applicazione deve accedere a funzionalità non appartenenti al tracciamento oculare standard, ad esempio i singoli vettori dello sguardo fisso o la modifica della frequenza dei fotogrammi del tracker.

Lo sguardo fisso combinato è una funzionalità obbligatoria supportata da tutti i tracker dello sguardo fisso. Altre funzionalità, ad esempio l'accesso al singolo sguardo fisso, sono facoltative e potrebbero essere supportate o meno a seconda del tracker e del relativo driver. Per queste funzionalità facoltative, la EyeGazeTracker classe espone una proprietà che indica se la funzionalità è supportata, ad esempio la AreLeftAndRightGazesSupported proprietà , che indica se le singole informazioni sullo sguardo fisso sono supportate dal dispositivo.

Tutte le informazioni spaziali esposte dallo sguardo fisso vengono pubblicate in relazione a un tracker stesso, identificato da un ID nodo dinamico. L'uso del nodeId per ottenere un SpatialCoordinateSystem oggetto con le API WinRT potrebbe trasformare le coordinate dei dati dello sguardo fisso in un altro sistema di coordinate.

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

Impostare la frequenza dei fotogrammi dello sguardo fisso

La EyeGazeTracker.SupportedTargetFrameRates proprietà restituisce l'elenco della frequenza dei fotogrammi di destinazione supportata dal tracker. HoloLens 2 supporta 30, 60 e 90fps.

Usare il EyeGazeTracker.SetTargetFrameRate() metodo per impostare la frequenza dei fotogrammi di destinazione.

// 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();

Legge i dati dello sguardo fisso dal tracker dello sguardo fisso

Un tracciamento sguardo fisso pubblica periodicamente i relativi stati in un buffer circolare. Ciò consente all'applicazione di leggere lo stato del tracker alla volta appartenente a un piccolo intervallo di tempo. Consente, ad esempio, il recupero dello stato più recente del tracker o il relativo stato al momento di un evento, ad esempio un gesto della mano dall'utente.

Metodi che recuperano lo stato del tracker come EyeGazeTrackerReading istanza:

  • I TryGetReadingAtTimestamp() metodi e TryGetReadingAtSystemRelativeTime() restituiscono il EyeGazeTrackerReading più vicino al tempo trascorso dall'applicazione. Il tracker controlla la pianificazione della pubblicazione, quindi la lettura restituita potrebbe essere leggermente precedente o successiva rispetto all'ora della richiesta. Le EyeGazeTrackerReading.Timestamp proprietà e EyeGazeTrackerReading.SystemRelativeTime consentono all'applicazione di conoscere l'ora esatta dello stato pubblicato.

  • I TryGetReadingAfterTimestamp() metodi e TryGetReadingAfterSystemRelativeTime() restituiscono il primo EyeGazeTrackerReading con un timestamp rigorosamente superiore al tempo passato come parametro. Ciò consente a un'applicazione di leggere in sequenza tutti gli stati pubblicati dal tracker. Si noti che tutti questi metodi eseguono query sul buffer esistente e che restituiscono immediatamente. Se non è disponibile alcuno stato, restituirà Null(in altre parole, non farà attendere la pubblicazione di uno stato dell'applicazione).

Oltre al timestamp, un'istanza EyeGazeTrackerReading ha una IsCalibrationValid proprietà , che indica se la calibrazione del tracciamento oculare è valida o meno.

Infine, i dati dello sguardo fisso possono essere recuperati tramite un set di metodi, TryGetCombinedEyeGazeInTrackerSpace() ad esempio o TryGetLeftEyeGazeInTrackerSpace(). Tutti questi metodi restituiscono un valore booleano che indica un esito positivo. L'impossibilità di ottenere alcuni dati potrebbe significare che i dati non sono supportati (EyeGazeTracker con proprietà per rilevare questo caso) o che il tracker non è riuscito a ottenere i dati (ad esempio, calibrazione non valida o occhio nascosto).

Se, ad esempio, l'applicazione vuole visualizzare un cursore corrispondente allo sguardo fisso combinato, può eseguire una query sul tracker usando un timestamp della stima del frame preparato come indicato di seguito.

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

Trasformare i dati dello sguardo fisso in altri spatialCoordinateSystem

Le API WinRT che restituiscono dati spaziali, ad esempio una posizione, richiedono sempre sia un oggetto che un PerceptionTimestamp .SpatialCoordinateSystem Ad esempio, per recuperare lo sguardo combinato di HoloLens 2 usando l'API WinRT, l'API SpatialPointerPose.TryGetAtTimestamp() richiede due parametri: a SpatialCoordinateSystem e .PerceptionTimestamp Quando si accede allo sguardo combinato tramite SpatialPointerPose.Eyes.Gaze, l'origine e la direzione vengono espresse nell'oggetto SpatialCoordinateSystem passato.

Le API DELL'SDK di rilevamento dei tie estesi non devono prendere un e SpatialCoordinateSystem i dati dello sguardo fisso sono sempre espressi nel sistema di coordinate del tracker. È tuttavia possibile trasformare i dati dello sguardo fisso in un altro sistema di coordinate con la posizione del tracker correlata all'altro sistema di coordinate.

  • Come indicato nella sezione precedente denominata "Open eye gaze tracker", per ottenere un SpatialLocator oggetto per lo sguardo fisso, chiamare Windows.Perception.Spatial.Preview.SpatialGraphInteropPreview.CreateLocatorForNode() con la EyeGazeTracker.TrackerSpaceLocatorNodeId proprietà .

  • Le origini dello sguardo fisso e le direzioni recuperate attraverso EyeGazeTrackerReading sono correlate al tracciatore dello sguardo fisso.

  • SpatialLocator.TryLocateAtTimestamp() restituisce la posizione 6DoF completa del tracker dello sguardo fisso in corrispondenza di un dato PerceptionTimeStamp oggetto e correlato a un determinato SpatialCoordinateSystemoggetto , che può essere usato per costruire una matrice di trasformazione Matrix4x4.

  • Usare la matrice di trasformazione Matrix4x4 costruita per trasferire le origini e le direzioni dello sguardo fisso ad altri SpatialCoordinateSystem.

Gli esempi di codice seguenti illustrano come calcolare la posizione di un cubo che si trova nella direzione dello sguardo combinato, due metri davanti all'origine dello sguardo fisso;

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

Informazioni di riferimento sulle API di Extended Eye Tracking SDK

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

Vedi anche