XRFaceSubsystem.cs
10.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
using System;
using Unity.Collections;
#if UNITY_2020_2_OR_NEWER
using UnityEngine.SubsystemsImplementation;
#endif
namespace UnityEngine.XR.ARSubsystems
{
/// <summary>
/// An abstract class that provides a generic API for low-level face tracking features.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
#if UNITY_2020_2_OR_NEWER
public class XRFaceSubsystem
: TrackingSubsystem<XRFace, XRFaceSubsystem, XRFaceSubsystemDescriptor, XRFaceSubsystem.Provider>
#else
public abstract class XRFaceSubsystem
: TrackingSubsystem<XRFace, XRFaceSubsystemDescriptor>
#endif
{
/// <summary>
/// Constructs a face subsystem. Do not invoked directly; call <c>Create</c> on the <see cref="XRFaceSubsystemDescriptor"/> instead.
/// </summary>
public XRFaceSubsystem()
{
#if !UNITY_2020_2_OR_NEWER
provider = CreateProvider();
#endif
}
#if !UNITY_2020_2_OR_NEWER
/// <summary>
/// Start the face subsystem, i.e., start tracking faces.
/// </summary>
protected sealed override void OnStart() => provider.Start();
/// <summary>
/// Destroy the face subsystem.
/// </summary>
protected sealed override void OnDestroyed() => provider.Destroy();
/// <summary>
/// Stop the subsystem, i.e., stop tracking faces.
/// </summary>
protected sealed override void OnStop() => provider.Stop();
#endif
/// <summary>
/// Get or set the maximum number of faces to track simultaneously.
/// </summary>
/// <exception cref="System.ArgumentOutOfRangeException">Thrown if the requested maximum face count is less than
/// one. To stop face tracking, call <see cref="XRSubsystem{TSubsystemDescriptor}.Stop()"/>.</exception>
/// <exception cref="System.NotSupportedException">Thrown if the requested maximum face count is greater than
/// one but the subsystem does not support tracking multiple faces.</exception>
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;
}
}
/// <summary>
/// Get the maximum number of faces the provider will simultaneously track.
/// </summary>
public int currentMaximumFaceCount => provider.currentMaximumFaceCount;
/// <summary>
/// Get the number of faces the subsystem is able to track simultaneously in its current configuration.
/// </summary>
public int supportedFaceCount => provider.supportedFaceCount;
/// <summary>
/// Get the changes (added, updated, and removed) faces since the last call to <see cref="GetChanges(Allocator)"/>.
/// </summary>
/// <param name="allocator">An <c>Allocator</c> to use when allocating the returned <c>NativeArray</c>s.</param>
/// <returns>
/// <see cref="TrackableChanges{T}"/> describing the faces that have been added, updated, and removed
/// since the last call to <see cref="GetChanges(Allocator)"/>. The caller owns the memory allocated with <c>Allocator</c>.
/// </returns>
public override TrackableChanges<XRFace> GetChanges(Allocator allocator)
{
using (new ScopedProfiler("GetChanges"))
{
var changes = provider.GetChanges(XRFace.defaultValue, allocator);
#if DEVELOPMENT_BUILD || UNITY_EDITOR
m_ValidationUtility.ValidateAndDisposeIfThrown(changes);
#endif
return changes;
}
}
/// <summary>
/// Get the mesh data associated with the face with <paramref name="faceId"/>. The <paramref name="faceMesh"/>
/// is reused if it is the correct size, otherwise, it is disposed and reallocated using <paramref name="allocator"/>.
/// </summary>
/// <param name="faceId">The <see cref="TrackableId"/> for a <see cref="XRFace"/>.</param>
/// <param name="allocator">The allocator to use for the returned data if a resize is necessary. Must be <c>Allocator.TempJob</c> or <c>Allocator.Persistent</c>.</param>
/// <param name="faceMesh">The container for the mesh data to either re-use or re-allocate.</param>
/// <exception cref="System.InvalidOperationException">Thrown if <paramref name="allocator"/> is <c>Allocator.Temp</c></exception>
/// <exception cref="System.InvalidOperationException">Thrown if <paramref name="allocator"/> is <c>Allocator.None</c></exception>
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);
}
#if !UNITY_2020_2_OR_NEWER
/// <summary>
/// Creates an instance of an implementation-specific <see cref="Provider"/>.
/// </summary>
/// <returns>An implementation of the <see cref="Provider"/> class.</returns>
protected abstract Provider CreateProvider();
#endif
/// <summary>
/// Class to be implemented by an implementor of the <see cref="XRFaceSubsystem"/>.
/// </summary>
public abstract class Provider
#if UNITY_2020_2_OR_NEWER
: SubsystemProvider<XRFaceSubsystem>
#endif
{
#if !UNITY_2020_2_OR_NEWER
/// <summary>
/// Called by <see cref="XRSubsystem{TSubsystemDescriptor}.OnStart()"/>. Only invoked if not already running.
/// </summary>
public virtual void Start() { }
/// <summary>
/// Called by <see cref="XRSubsystem{TSubsystemDescriptor}.OnStop()"/>. Only invoked if current running.
/// </summary>
public virtual void Stop() { }
/// <summary>
/// Called by <see cref="XRSubsystem{TSubsystemDescriptor}.OnDestroy()"/> when the subsystem is destroyed.
/// </summary>
public virtual void Destroy() { }
#endif
/// <summary>
/// Get the mesh data associated with the face with <paramref name="faceId"/>. The <paramref name="faceMesh"/>
/// should be reused if it is the correct size, otherwise, its arrays should be reallocated with <paramref name="allocator"/>.
/// Use <see cref="XRFaceMesh.Resize"/> to resize the containers for face mesh data.
/// </summary>
/// <param name="faceId">The <see cref="TrackableId"/> for a <see cref="XRFace"/>.</param>
/// <param name="allocator">The allocator to use for the returned data if a resize is necessary.</param>
/// <param name="faceMesh">The container for the mesh data to either re-use or re-allocate.</param>
/// <example>
/// <code>
/// var vertices = faceMesh.vertices;
/// CreateOrResizeNativeArrayIfNecessary(numVertices, allocator, ref vertices);
///
/// ...
///
/// faceMesh.Assign(new XRFaceMesh
/// {
/// vertices = vertices,
/// indices = ...
/// });
/// </code>
/// </example>
public virtual void GetFaceMesh(TrackableId faceId, Allocator allocator, ref XRFaceMesh faceMesh)
{
faceMesh.Dispose();
faceMesh = default(XRFaceMesh);
}
/// <summary>
/// Get the changes (added, updated, and removed) faces since the last call to <see cref="GetChanges(XRFace,Allocator)"/>.
/// </summary>
/// <param name="defaultFace">
/// The default face. This should be used to initialize the returned <c>NativeArray</c>s for backwards compatibility.
/// See <see cref="TrackableChanges{T}.TrackableChanges(void*, int, void*, int, void*, int, T, int, Unity.Collections.Allocator)"/>.
/// </param>
/// <param name="allocator">An <c>Allocator</c> to use when allocating the returned <c>NativeArray</c>s.</param>
/// <returns>
/// <see cref="TrackableChanges{T}"/> describing the faces that have been added, updated, and removed
/// since the last call to <see cref="GetChanges(XRFace,Allocator)"/>. The changes should be allocated using
/// <paramref name="allocator"/>.
/// </returns>
public abstract TrackableChanges<XRFace> GetChanges(XRFace defaultFace, Allocator allocator);
/// <summary>
/// Should return the maximum number of faces the subsystem is able to track simultaneously.
/// Defaults to 1.
/// </summary>
public virtual int supportedFaceCount => 1;
/// <summary>
/// Get or set the maximum number of faces the subsystem should attempt to track simultaneously.
/// Defaults to 1.
/// </summary>
/// <exception cref="System.NotSupportedException">Thrown if the requested maximum face count is greater than one but the subsystem does not support tracking multiple faces.</exception>
public virtual int requestedMaximumFaceCount
{
get => m_RequestedMaximumFaceCount;
set => m_RequestedMaximumFaceCount = value;
}
int m_RequestedMaximumFaceCount = 1;
/// <summary>
/// Gets the maximum number of faces the provider will track.
/// </summary>
public virtual int currentMaximumFaceCount => 1;
}
#if !UNITY_2020_2_OR_NEWER
/// <summary>
/// The provider created by the implementation that contains the required face tracking functionality.
/// </summary>
protected Provider provider { get; }
#endif
#if DEVELOPMENT_BUILD || UNITY_EDITOR
ValidationUtility<XRFace> m_ValidationUtility =
new ValidationUtility<XRFace>();
#endif
}
}