using System; using Unity.Collections; namespace UnityEngine.XR.ARSubsystems { /// /// An abstract class that provides a generic API for low-level face tracking features. /// /// /// This class can be used to access face tracking features in your app via accessing the generic API. /// It can also be extended to provide an implementation of a provider which provides the face tracking data /// to the higher level code. /// public abstract class XRFaceSubsystem : TrackingSubsystem { /// /// Constructs a face subsystem. Do not invoked directly; call Create on the instead. /// public XRFaceSubsystem() => m_Provider = CreateProvider(); /// /// Start the face subsystem, i.e., start tracking faces. /// protected sealed override void OnStart() => m_Provider.Start(); /// /// Destroy the face subsystem. /// protected sealed override void OnDestroyed() => m_Provider.Destroy(); /// /// Stop the subsystem, i.e., stop tracking faces. /// protected sealed override void OnStop() => m_Provider.Stop(); /// /// Get or set the maximum number of faces to track simultaneously. /// public int maximumFaceCount { get => m_Provider.maximumFaceCount; set => m_Provider.maximumFaceCount = value; } /// /// Get the number of faces the subsystem is able to track simultaneously. /// public int supportedFaceCount => m_Provider.supportedFaceCount; /// /// Get the changes (added, updated, and removed) faces 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 = m_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."); m_Provider.GetFaceMesh(faceId, allocator, ref faceMesh); } /// /// Creates an instance of an implementation-specific . /// /// An implementation of the class. protected abstract Provider CreateProvider(); /// /// Class to be implemented by an implementor of the . /// protected abstract class Provider { /// /// Called by . Only invoked if not already running. /// public virtual void Start() { } /// /// Called by . Only invoked if current running. /// public virtual void Stop() { } /// /// Called by when the subsystem is destroyed. /// public virtual void Destroy() { } /// /// 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 ensure unused NativeArrays are disposed properly and /// to resize individual arrays. /// /// 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(XRFaceMesh); } /// /// Get the changes (added, updated, and removed) faces 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. /// public virtual int maximumFaceCount { get => 1; set { if (maximumFaceCount < 1) throw new ArgumentOutOfRangeException("value", "Must track at least one face. Call Stop() if you wish to stop face tracking."); if (maximumFaceCount > 1) throw new NotSupportedException("This subsystem does not support multiple faces."); } } } Provider m_Provider; #if DEVELOPMENT_BUILD || UNITY_EDITOR ValidationUtility m_ValidationUtility = new ValidationUtility(); #endif } }