Расширенное отслеживание взгляда в Unity

Чтобы получить доступ к репозиторию GitHub для примера расширенного отслеживания глаз, выполните следующие действия.

Расширенное отслеживание взгляда — это новая возможность в HoloLens 2. Это супермножество стандартного отслеживания взгляда, которое предоставляет только объединенные данные взгляда. Расширенное отслеживание взгляда также предоставляет отдельные данные о взгляде и позволяет приложениям задавать разные частоты кадров для данных взгляда, например 30, 60 и 90 кадров в секунду. Другие функции, такие как открытость глаз и вергенция глаз, в настоящее время не поддерживаются HoloLens 2.

Пакет SDK для расширенного отслеживания глаз позволяет приложениям получать доступ к данным и функциям расширенного отслеживания глаз. Его можно использовать вместе с API OpenXR или устаревшими API WinRT.

В этой статье рассматриваются способы использования пакета SDK для расширенного отслеживания взгляда в Unity вместе с подключаемым модулем Смешанная реальность OpenXR.

Настройка проекта

  1. Настройте проект Unity для разработки HoloLens.
    • Выбор возможности "Вход взгляда"
  2. Импортируйте подключаемый модуль OpenXR Смешанная реальность из средства функций MRTK.
  3. Импортируйте пакет NuGet пакета NuGet для отслеживания глаз в проект Unity.
    1. Скачайте и установите пакет NuGetForUnity .
    2. В редакторе Unity перейдите в NuGetраздел ->Manage NuGet Packages, а затем найдите Microsoft.MixedReality.EyeTracking
    3. Нажмите кнопку Установить, чтобы импортировать последнюю версию пакета NuGet.
      Снимок экрана пакета Nuget пакета SDK для отслеживания глаз.
  4. Добавьте вспомогательные скрипты Unity.
    1. ExtendedEyeGazeDataProvider.cs Добавьте скрипт отсюда в проект Unity.
    2. Создайте сцену, а затем вложите сценарий в ExtendedEyeGazeDataProvider.cs любой GameObject.
  5. Используйте функции ExtendedEyeGazeDataProvider.cs и реализуйте логику.
  6. Выполните сборку и развертывание в HoloLens.

Использование функций ExtendedEyeGazeDataProvider

Примечание

Скрипт ExtendedEyeGazeDataProvider зависит от некоторых API из подключаемого модуля OpenXR Смешанная реальность для преобразования координат данных взгляда. Он не может работать, если в проекте Unity используется устаревший подключаемый модуль Windows XR или устаревший встроенный XR в более старой версии Unity. Чтобы расширенное отслеживание глаз также работало в следующих сценариях:

  • Если вам просто нужно получить доступ к параметрам частоты кадров, Смешанная реальность подключаемый модуль OpenXR не требуется, и вы можете изменить ExtendedEyeGazeDataProvider , чтобы сохранить только логику, связанную с частотой кадров.
  • Если вам по-прежнему требуется доступ к отдельным данным взгляда, необходимо использовать API WinRT в Unity. Сведения об использовании пакета SDK для расширенного отслеживания глаз с API WinRT см. в разделе "См. также".

Класс ExtendedEyeGazeDataProvider упаковывает API-интерфейсы пакета SDK для расширенного отслеживания взгляда. Он предоставляет функции для получения считывания взгляда в пространстве мира Unity или относительно main камеры.

Ниже приведены примеры кода для получения ExtendedEyeGazeDataProvider данных взгляда.

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

При выполнении ExtendedEyeGazeDataProvider скрипта для частоты кадров данных взгляда устанавливается самый высокий параметр, который в настоящее время составляет 90 кадров в секунду.

Справочник по API для пакета SDK для расширенного отслеживания глаз

Помимо использования скрипта ExtendedEyeGazeDataProvider , вы также можете создать собственный скрипт для непосредственного использования API пакета 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);
    }
}

См. также раздел