using System; using Unity.Collections; using UnityEngine.SubsystemsImplementation; namespace UnityEngine.XR.ARSubsystems { /// /// An abstract class that provides a generic API for low-level face tracking features. /// /// /// Use this class to access face tracking features in your app via accessing the generic API. /// You can also extend it to provide an implementation of a provider which provides the face tracking data /// to the higher-level code. /// public class XRFaceSubsystem : TrackingSubsystem { #if DEVELOPMENT_BUILD || UNITY_EDITOR ValidationUtility m_ValidationUtility = new(); #endif /// /// Constructs a face subsystem. Do not invoke directly; call Create on the instead. /// public XRFaceSubsystem() { } /// /// Get or set the maximum number of faces to track simultaneously. /// /// Thrown if the requested maximum face count is less than /// one. To stop face tracking, call . /// Thrown if the requested maximum face count is greater than /// one but the subsystem does not support tracking multiple faces. public int requestedMaximumFaceCount { get => provider.requestedMaximumFaceCount; set { if (value < 1) throw new ArgumentOutOfRangeException("value", "Must track at least one face. Call Stop() if you wish to stop face tracking."); provider.requestedMaximumFaceCount = value; } } /// /// Get the maximum number of faces the provider will simultaneously track. /// public int currentMaximumFaceCount => provider.currentMaximumFaceCount; /// /// Get the number of faces the subsystem is able to track simultaneously in its current configuration. /// public int supportedFaceCount => provider.supportedFaceCount; /// /// Get the changes to faces (added, updated, and removed) since the last call to . /// /// An Allocator to use when allocating the returned NativeArrays. /// /// describing the faces that have been added, updated, and removed /// since the last call to . The caller owns the memory allocated with Allocator. /// public override TrackableChanges GetChanges(Allocator allocator) { var changes = provider.GetChanges(XRFace.defaultValue, allocator); #if DEVELOPMENT_BUILD || UNITY_EDITOR m_ValidationUtility.ValidateAndDisposeIfThrown(changes); #endif return changes; } /// /// Get the mesh data associated with the face with . The /// is reused if it is the correct size; otherwise, it is disposed and reallocated using . /// /// The for a . /// The allocator to use for the returned data if a resize is necessary. Must be Allocator.TempJob or Allocator.Persistent. /// The container for the mesh data to either re-use or re-allocate. /// Thrown if is Allocator.Temp /// Thrown if is Allocator.None public virtual void GetFaceMesh(TrackableId faceId, Allocator allocator, ref XRFaceMesh faceMesh) { if (allocator == Allocator.Temp) throw new InvalidOperationException("Allocator.Temp is not supported. Use Allocator.TempJob if you wish to use a temporary allocator."); if (allocator == Allocator.None) throw new InvalidOperationException("Allocator.None is not a valid allocator."); using (new ScopedProfiler("GetFaceMesh")) provider.GetFaceMesh(faceId, allocator, ref faceMesh); } /// /// Class to be implemented by an implementor of the . /// public abstract class Provider : SubsystemProvider { /// /// Get the mesh data associated with the face with . The /// should be reused if it is the correct size; otherwise, its arrays should be reallocated with . /// Use to resize the containers for face mesh data. /// /// The for a . /// The allocator to use for the returned data if a resize is necessary. /// The container for the mesh data to either re-use or re-allocate. /// /// /// var vertices = faceMesh.vertices; /// CreateOrResizeNativeArrayIfNecessary(numVertices, allocator, ref vertices); /// /// ... /// /// faceMesh.Assign(new XRFaceMesh /// { /// vertices = vertices, /// indices = ... /// }); /// /// public virtual void GetFaceMesh(TrackableId faceId, Allocator allocator, ref XRFaceMesh faceMesh) { faceMesh.Dispose(); faceMesh = default; } /// /// Get the changes to faces (added, updated, and removed) since the last call to . /// /// /// The default face. This should be used to initialize the returned NativeArrays for backwards compatibility. /// See . /// /// An Allocator to use when allocating the returned NativeArrays. /// /// describing the faces that have been added, updated, and removed /// since the last call to . The changes should be allocated using /// . /// public abstract TrackableChanges GetChanges(XRFace defaultFace, Allocator allocator); /// /// Should return the maximum number of faces the subsystem is able to track simultaneously. /// Defaults to 1. /// public virtual int supportedFaceCount => 1; /// /// Get or set the maximum number of faces the subsystem should attempt to track simultaneously. /// Defaults to 1. /// /// Thrown if the requested maximum face count is greater than one, but the subsystem does not support tracking multiple faces. public virtual int requestedMaximumFaceCount { get => m_RequestedMaximumFaceCount; set => m_RequestedMaximumFaceCount = value; } int m_RequestedMaximumFaceCount = 1; /// /// Gets the maximum number of faces the provider will track. /// public virtual int currentMaximumFaceCount => 1; } } }