Compartir a través de


Seguimiento ocular extendido en Unity

Para acceder al repositorio de GitHub para el ejemplo de seguimiento ocular extendido:

El seguimiento ocular extendido es una nueva funcionalidad en HoloLens 2. Es un superconjunto del seguimiento ocular estándar, que solo proporciona datos combinados de mirada ocular. El seguimiento extendido de los ojos también proporciona datos de mirada ocular individuales y permite a las aplicaciones establecer diferentes velocidades de fotogramas para los datos de mirada, como 30, 60 y 90fps. Otras características, como la apertura ocular y la vergüencia ocular, no son compatibles con HoloLens 2 en este momento.

El SDK de seguimiento ocular extendido permite a las aplicaciones acceder a los datos y características del seguimiento ocular extendido. Se podría usar junto con las API de OpenXR o las API de WinRT heredadas.

En este artículo se tratan las formas de usar el SDK de seguimiento ocular extendido en Unity junto con el complemento openXR de Mixed Reality.

Configuración del proyecto

  1. Configure el proyecto de Unity para el desarrollo de HoloLens.
    • Seleccione la funcionalidad Entrada de mirada.
  2. Importe la Mixed Reality complemento OpenXR desde la herramienta de características MRTK.
  3. Importe el paquete NuGet del SDK de Seguimiento ocular en el proyecto de Unity.
    1. Descargue e instale el paquete NuGetForUnity .
    2. En el editor de Unity, vaya a NuGet->Manage NuGet Packagesy busque Microsoft.MixedReality.EyeTracking
    3. Haga clic en el botón Instalar para importar la versión más reciente del paquete NuGet.
      Captura de pantalla del paquete NuGet del SDK de Seguimiento ocular.
  4. Agregue los scripts auxiliares de Unity.
    1. Agregue el ExtendedEyeGazeDataProvider.cs script desde aquí al proyecto de Unity.
    2. Cree una escena y, a continuación, adjunte el ExtendedEyeGazeDataProvider.cs script a cualquier GameObject.
  5. Consuma las funciones de ExtendedEyeGazeDataProvider.cs e implemente las lógicas.
  6. Compile e implemente en HoloLens.

Consumo de funciones de ExtendedEyeGazeDataProvider

Nota

El ExtendedEyeGazeDataProvider script depende de algunas API del complemento de Mixed Reality OpenXR para convertir las coordenadas de los datos de mirada. No puede funcionar si el proyecto de Unity usa el complemento de Windows XR en desuso o el XR integrado heredado en la versión anterior de Unity. Para que el seguimiento ocular extendido funcione también en esos escenarios:

  • Si solo necesita acceder a la configuración de velocidad de fotogramas, el Mixed Reality complemento OpenXR no es necesario y podría modificar para ExtendedEyeGazeDataProvider que solo mantenga la lógica relacionada con la velocidad de fotogramas.
  • Si todavía necesita acceder a datos individuales de mirada ocular, debe usar las API de WinRT en Unity. Para ver cómo usar el SDK de seguimiento ocular extendido con las API de WinRT, consulte la sección "Ver también".

La ExtendedEyeGazeDataProvider clase ajusta las API del SDK de seguimiento ocular extendido. Proporciona funciones para leer la mirada en el espacio mundial de Unity o en relación con la cámara principal.

Estos son ejemplos de código para consumir ExtendedEyeGazeDataProvider para obtener los datos de mirada.

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

Cuando se ejecuta el ExtendedEyeGazeDataProvider script, establece la velocidad de fotogramas de datos de mirada en la opción más alta, que actualmente es de 90 fps.

Referencia de API del SDK de seguimiento ocular extendido

Además de usar el ExtendedEyeGazeDataProvider script, también puede crear su propio script para consumir directamente las API del 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);
    }
}

Consulte también