Расширенное отслеживание взгляда в Unity
Чтобы получить доступ к репозиторию GitHub для примера расширенного отслеживания глаз, выполните следующие действия.
Расширенное отслеживание взгляда — это новая возможность в HoloLens 2. Это супермножество стандартного отслеживания взгляда, которое предоставляет только объединенные данные взгляда. Расширенное отслеживание взгляда также предоставляет отдельные данные о взгляде и позволяет приложениям задавать разные частоты кадров для данных взгляда, например 30, 60 и 90 кадров в секунду. Другие функции, такие как открытость глаз и вергенция глаз, в настоящее время не поддерживаются HoloLens 2.
Пакет SDK для расширенного отслеживания глаз позволяет приложениям получать доступ к данным и функциям расширенного отслеживания глаз. Его можно использовать вместе с API OpenXR или устаревшими API WinRT.
В этой статье рассматриваются способы использования пакета SDK для расширенного отслеживания взгляда в Unity вместе с подключаемым модулем Смешанная реальность OpenXR.
Настройка проекта
-
Настройте проект Unity для разработки HoloLens.
- Выбор возможности "Вход взгляда"
- Импортируйте подключаемый модуль OpenXR Смешанная реальность из средства функций MRTK.
- Импортируйте пакет NuGet пакета NuGet для отслеживания глаз в проект Unity.
- Скачайте и установите пакет NuGetForUnity .
- В редакторе Unity перейдите в
NuGet
раздел ->Manage NuGet Packages
, а затем найдитеMicrosoft.MixedReality.EyeTracking
- Нажмите кнопку Установить, чтобы импортировать последнюю версию пакета NuGet.
- Добавьте вспомогательные скрипты Unity.
-
ExtendedEyeGazeDataProvider.cs
Добавьте скрипт отсюда в проект Unity. - Создайте сцену, а затем вложите сценарий в
ExtendedEyeGazeDataProvider.cs
любой GameObject.
-
- Используйте функции
ExtendedEyeGazeDataProvider.cs
и реализуйте логику. - Выполните сборку и развертывание в 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);
}
}