네이티브 엔진의 확장된 시선 추적

확장된 시선 추적은 HoloLens 2 새로운 기능입니다. 결합된 시선 응시 데이터만 제공하는 표준 시선 추적의 상위 집합입니다. 또한 확장된 시선 추적은 개별 시선 응시 데이터를 제공하며 애플리케이션이 응시 데이터에 대해 30, 60 및 90fps와 같은 다양한 프레임 속도를 설정할 수 있도록 합니다. 눈 개방성 및 눈 버지와 같은 다른 기능은 현재 HoloLens 2 지원하지 않습니다.

확장 아이 트래킹 SDK를 사용하면 애플리케이션이 확장된 시선 추적의 데이터 및 기능에 액세스할 수 있습니다. WinRT API 또는 OpenXR API와 함께 사용할 수 있습니다.

이 문서에서는 WinRT API와 함께 네이티브 엔진(C# 또는 C++/WinRT)에서 확장된 시선 추적 SDK를 사용하는 방법을 설명합니다.

프로젝트 설정

  1. Holographic DirectX 11 App (Universal Windows) Visual Studio 2019 이상을 사용하여 또는 Holographic DirectX 11 App (Universal Windows) (C++/WinRT) 프로젝트를 만들거나 기존 홀로그램 Visual Studio 프로젝트를 엽니다.
  2. 확장된 시선 추적 SDK를 프로젝트로 가져옵니다.
    1. Visual Studio 솔루션 탐색기 프로젝트 -> NuGet 패키지 관리...를 마우스 오른쪽 단추로 클릭합니다.
    2. 오른쪽 위 모서리에 있는 패키지 원본이 nuget.org 가리키는지 확인합니다. https://api.nuget.org/v3/index.json
    3. 브라우저 탭을 클릭한 다음 를 검색 Microsoft.MixedReality.EyeTracking합니다.
    4. 설치 단추를 클릭하여 최신 버전의 SDK를 설치합니다.
      시선 추적 SDK Nuget 패키지의 스크린샷.
  3. 응시 입력 기능 설정
    1. 솔루션 탐색기 Package.appxmanifest 파일을 두 번 클릭합니다.
    2. 기능 탭을 클릭한 다음 응시 입력을 검사.
  4. 헤드 파일을 포함하고 네임스페이스를 사용합니다.
    • C# 프로젝트의 경우:
    using Microsoft.MixedReality.EyeTracking;
    
    • C++/WinRT 프로젝트의 경우:
    #include <winrt/Microsoft.MixedReality.EyeTracking.h>
    using namespace winrt::Microsoft::MixedReality::EyeTracking;
    
  5. 확장된 시선 추적 SDK API를 사용하고 논리를 구현합니다.
  6. HoloLens를 빌드하고 배포합니다.

응시 데이터를 가져오는 단계 개요

확장 눈 추적 SDK API를 통해 시선 응시 데이터를 가져오려면 다음 단계가 필요합니다.

  1. 사용자로부터 시선 추적 기능에 대한 액세스 권한을 얻습니다.
  2. 시선 응시 추적기 연결 및 연결 끊김을 확인합니다.
  3. 시선 응시 추적기를 열고 해당 기능을 쿼리합니다.
  4. 시선 응시 추적기에서 응시 데이터를 반복적으로 읽습니다.
  5. 응시 데이터를 다른 SpatialCoordinateSystems로 전송합니다.

시선 추적 기능에 대한 액세스 권한 얻기

눈 관련 정보를 사용하려면 애플리케이션에서 먼저 사용자 동의를 요청해야 합니다.

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

시선 응시 추적기 감지

시선 응시 추적기는 클래스를 사용하여 검색됩니다 EyeGazeTrackerWatcher . EyeGazeTrackerAddedEyeGazeTrackerRemoved 이벤트는 시선 응시 추적기가 감지되거나 연결이 끊어지면 각각 발생합니다.

감시자는 메서드로 StartAsync() 명시적으로 시작해야 합니다. 이 메서드는 이미 연결된 추적기가 이벤트를 통해 EyeGazeTrackerAdded 신호를 받으면 비동기적으로 완료됩니다.

시선 응시 추적기가 감지되면 EyeGazeTracker 이벤트 매개 변수에서 instance 애플리케이션에 EyeGazeTrackerAdded 전달됩니다. 역순으로 추적기가 연결이 끊어지면 해당 EyeGazeTracker instance 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)
{
    ...
}

시선 응시 추적기 열기

instance 받을 EyeGazeTracker 때 애플리케이션은 먼저 메서드를 호출 OpenAsync() 하여 열어야 합니다. 그런 다음 필요한 경우 추적기 기능을 쿼리할 수 있습니다. 메서드는 OpenAsync() 부울 매개 변수를 사용합니다. 이는 애플리케이션이 개별 시선 응시 벡터 또는 트래커의 프레임 속도 변경과 같은 표준 시선 추적에 속하지 않는 기능에 액세스해야 하는지 여부를 나타냅니다.

결합된 응시는 모든 시선 응시 추적기에서 지원하는 필수 기능입니다. 개별 응시에 대한 액세스와 같은 다른 기능은 선택 사항이며 추적기 및 드라이버에 따라 지원되거나 지원되지 않을 수 있습니다. 이러한 선택적 기능의 EyeGazeTracker 경우 클래스는 기능이 지원되는지 여부를 나타내는 속성(예 AreLeftAndRightGazesSupported : 디바이스에서 개별 시선 응시 정보를 지원하는지 여부를 나타내는 속성)을 노출합니다.

시선 응시 추적기에서 노출되는 모든 공간 정보는 동적 노드 ID로 식별되는 추적기 자체와 관련하여 게시됩니다. nodeId를 사용하여 WinRT API를 사용하여 를 SpatialCoordinateSystem 가져오면 응시 데이터의 좌표를 다른 좌표계로 변환할 수 있습니다.

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

시선 응시 추적기 프레임 속도 설정

속성은 EyeGazeTracker.SupportedTargetFrameRates 추적기에서 지원하는 대상 프레임 속도 목록을 반환합니다. HoloLens 2 30, 60 및 90fps를 지원합니다.

메서드를 EyeGazeTracker.SetTargetFrameRate() 사용하여 대상 프레임 속도를 설정합니다.

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

시선 응시 추적기에서 응시 데이터 읽기

시선 응시 추적기는 주기적으로 상태를 순환 버퍼에 게시합니다. 이렇게 하면 애플리케이션이 작은 시간 범위에 속하는 한 번에 추적기의 상태를 읽을 수 있습니다. 예를 들어 추적기의 가장 최근 상태 또는 사용자의 손 제스처와 같은 일부 이벤트 시의 상태를 검색할 수 있습니다.

추적기 상태를 instance 검색하는 EyeGazeTrackerReading 메서드:

  • 및 메서드는 TryGetReadingAtTimestamp() 애플리케이션에서 EyeGazeTrackerReading 경과한 시간에 가장 가까운 을 반환 TryGetReadingAtSystemRelativeTime() 합니다. 추적기는 게시 일정을 제어하므로 반환된 읽기는 요청 시간보다 약간 오래되거나 최신일 수 있습니다. EyeGazeTrackerReading.TimestampEyeGazeTrackerReading.SystemRelativeTime 속성을 사용하면 애플리케이션이 게시된 상태의 정확한 시간을 알 수 있습니다.

  • TryGetReadingAfterSystemRelativeTime() 메서드는 TryGetReadingAfterTimestamp() 매개 변수로 전달된 시간보다 엄격하게 우수한 타임스탬프를 사용하여 첫 번째 EyeGazeTrackerReading 를 반환합니다. 이렇게 하면 애플리케이션이 추적기에서 게시한 모든 상태를 순차적으로 읽을 수 있습니다. 이러한 모든 메서드는 기존 버퍼를 쿼리하고 즉시 반환됩니다. 사용할 수 있는 상태가 없으면 null을 반환합니다(즉, 애플리케이션이 상태가 게시될 때까지 기다리지 않음).

타임스탬프 EyeGazeTrackerReading 외에도 instance IsCalibrationValid 아이 트래커 보정이 유효한지 여부를 나타내는 속성이 있습니다.

마지막으로, 응시 데이터는 또는 TryGetLeftEyeGazeInTrackerSpace()와 같은 TryGetCombinedEyeGazeInTrackerSpace() 메서드 집합을 통해 검색할 수 있습니다. 이러한 모든 메서드는 성공을 나타내는 부울을 반환합니다. 일부 데이터를 얻지 못하면 데이터가 지원되지 않거나(EyeGazeTracker 이 경우를 검색하는 속성이 있음) 추적기가 데이터를 가져올 수 없음을 의미할 수 있습니다(예: 잘못된 보정 또는 눈을 숨김).

예를 들어 애플리케이션이 결합된 응시에 해당하는 커서를 표시하려는 경우 다음과 같이 준비되는 프레임 예측의 타임스탬프를 사용하여 추적기를 쿼리할 수 있습니다.

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

응시 데이터를 다른 SpatialCoordinateSystem으로 변환

위치와 같은 공간 데이터를 반환하는 WinRT API에는 항상 와 SpatialCoordinateSystemPerceptionTimestamp 모두 필요합니다. 예를 들어 WinRT API를 사용하여 HoloLens 2 결합된 응시를 검색하려면 API SpatialPointerPose.TryGetAtTimestamp()에는 및 의 두 매개 변수가 SpatialCoordinateSystemPerceptionTimestamp필요합니다. 결합된 응시가 를 통해 SpatialPointerPose.Eyes.Gaze액세스되면 해당 원점과 방향이 전달된 에서 SpatialCoordinateSystem 표현됩니다.

확장된 타이 추적 SDK API는 를 SpatialCoordinateSystem 사용할 필요가 없으며 응시 데이터는 항상 추적기 좌표계에 표시됩니다. 그러나 다른 좌표계와 관련된 추적기 포즈를 사용하여 응시 데이터를 다른 좌표계로 변환할 수 있습니다.

  • 위의 "Open Eye Gaze Tracker"라는 섹션이 언급했듯이 시선 응시 추적기를 얻으려면 SpatialLocator 속성을 사용하여 를 호출 Windows.Perception.Spatial.Preview.SpatialGraphInteropPreview.CreateLocatorForNode()EyeGazeTracker.TrackerSpaceLocatorNodeId 합니다.

  • 통해 검색된 EyeGazeTrackerReading 응시 원점 및 방향은 시선 응시 추적기와 관련이 있습니다.

  • SpatialLocator.TryLocateAtTimestamp() 는 지정된 PerceptionTimeStamp 에 있는 시선 응시 추적기의 전체 6DoF 위치를 반환하며, 이는 Matrix4x4 변환 매트릭스를 구성하는 데 사용할 수 있는 지정된 SpatialCoordinateSystem와 관련이 있습니다.

  • 생성된 Matrix4x4 변환 매트릭스를 사용하여 응시 원점과 방향을 다른 SpatialCoordinateSystem으로 전송합니다.

다음 코드 샘플에서는 결합된 응시 방향에 있는 큐브의 위치를 계산하는 방법을 보여 줍니다. 응시 원점 앞의 2미터;

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

확장된 시선 추적 SDK의 API 참조

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

추가 정보