ARKitXRPlaneSubsystem.cs
8.54 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
using System.Runtime.InteropServices;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using UnityEngine.Scripting;
using UnityEngine.XR.ARSubsystems;
namespace UnityEngine.XR.ARKit
{
/// <summary>
/// The ARKit implementation of the <c>XRPlaneSubsystem</c>. Do not create this directly. Use the <c>SubsystemManager</c> instead.
/// </summary>
[Preserve]
public sealed class ARKitXRPlaneSubsystem : XRPlaneSubsystem
{
#if !UNITY_2020_2_OR_NEWER
/// <summary>
/// Creates the ARKit-specific implementation which will service the `XRPlaneSubsystem`.
/// </summary>
/// <returns>A new instance of the `Provider` specific to ARKit.</returns>
protected override Provider CreateProvider() => new ARKitProvider();
#endif
class ARKitProvider : Provider
{
public override void Destroy() => NativeApi.UnityARKit_Planes_Shutdown();
public override void Start() => NativeApi.UnityARKit_Planes_Start();
public override void Stop() => NativeApi.UnityARKit_Planes_Stop();
public override unsafe void GetBoundary(
TrackableId trackableId,
Allocator allocator,
ref NativeArray<Vector2> boundary)
{
int numPoints;
void* verticesPtr;
void* plane = NativeApi.UnityARKit_Planes_AcquireBoundary(
trackableId,
out verticesPtr,
out numPoints);
try
{
CreateOrResizeNativeArrayIfNecessary(numPoints, allocator, ref boundary);
var transformPositionsHandle = new TransformBoundaryPositionsJob
{
positionsIn = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<Vector4>(verticesPtr, numPoints, Allocator.None),
positionsOut = boundary
}.Schedule(numPoints, 1);
new FlipBoundaryWindingJob
{
positions = boundary
}.Schedule(transformPositionsHandle).Complete();
}
finally
{
NativeApi.UnityARKit_Planes_ReleaseBoundary(plane);
}
}
struct FlipBoundaryWindingJob : IJob
{
public NativeArray<Vector2> positions;
public void Execute()
{
var half = positions.Length / 2;
for (int i = 0; i < half; ++i)
{
var j = positions.Length - 1 - i;
var temp = positions[i];
positions[i] = positions[j];
positions[j] = temp;
}
}
}
struct TransformBoundaryPositionsJob : IJobParallelFor
{
[ReadOnly]
public NativeArray<Vector4> positionsIn;
[WriteOnly]
public NativeArray<Vector2> positionsOut;
public void Execute(int index)
{
positionsOut[index] = new Vector2(
// NB: https://developer.apple.com/documentation/arkit/arplanegeometry/2941052-boundaryvertices?language=objc
// "The owning plane anchor's transform matrix defines the coordinate system for these points."
// It doesn't explicitly state the y component is zero, but that must be the case if the
// boundary points are in plane-space. Emperically, it has been true for horizontal and vertical planes.
// This IS explicitly true for the extents (see above) and would follow the same logic.
//
// Boundary vertices are in right-handed coordinates and clockwise winding order. To convert
// to left-handed, we flip the Z coordinate, but that also flips the winding, so we have to
// flip the winding back to clockwise by reversing the polygon index (j).
positionsIn[index].x,
-positionsIn[index].z);
}
}
public override unsafe TrackableChanges<BoundedPlane> GetChanges(
BoundedPlane defaultPlane,
Allocator allocator)
{
int addedLength, updatedLength, removedLength, elementSize;
void* addedArrayPtr, updatedArrayPtr, removedArrayPtr;
var context = NativeApi.UnityARKit_Planes_AcquireChanges(
out addedArrayPtr, out addedLength,
out updatedArrayPtr, out updatedLength,
out removedArrayPtr, out removedLength,
out elementSize);
try
{
return new TrackableChanges<BoundedPlane>(
addedArrayPtr, addedLength,
updatedArrayPtr, updatedLength,
removedArrayPtr, removedLength,
defaultPlane, elementSize,
allocator);
}
finally
{
NativeApi.UnityARKit_Planes_ReleaseChanges(context);
}
}
public override PlaneDetectionMode requestedPlaneDetectionMode
{
get => NativeApi.UnityARKit_Planes_GetRequestedPlaneDetectionMode();
set => NativeApi.UnityARKit_Planes_SetRequestedPlaneDetectionMode(value);
}
}
/// <summary>
/// Container to wrap the native ARKit APIs needed at registration.
/// </summary>
static class NativeApi
{
[DllImport("__Internal")]
static internal extern unsafe bool UnityARKit_Planes_SupportsClassification();
[DllImport("__Internal")]
static internal extern void UnityARKit_Planes_Shutdown();
[DllImport("__Internal")]
static internal extern void UnityARKit_Planes_Start();
[DllImport("__Internal")]
static internal extern void UnityARKit_Planes_Stop();
[DllImport("__Internal")]
static internal extern unsafe void* UnityARKit_Planes_AcquireChanges(
out void* addedPtr, out int addedLength,
out void* updatedPtr, out int updatedLength,
out void* removedPtr, out int removedLength,
out int elementSize);
[DllImport("__Internal")]
static internal extern unsafe void UnityARKit_Planes_ReleaseChanges(void* changes);
[DllImport("__Internal")]
static internal extern PlaneDetectionMode UnityARKit_Planes_GetRequestedPlaneDetectionMode();
[DllImport("__Internal")]
static internal extern void UnityARKit_Planes_SetRequestedPlaneDetectionMode(PlaneDetectionMode mode);
[DllImport("__Internal")]
static internal extern PlaneDetectionMode UnityARKit_Planes_GetCurrentPlaneDetectionMode();
[DllImport("__Internal")]
static internal extern unsafe void* UnityARKit_Planes_AcquireBoundary(
TrackableId trackableId,
out void* verticiesPtr,
out int numPoints);
[DllImport("__Internal")]
static internal extern unsafe void UnityARKit_Planes_ReleaseBoundary(
void* boundary);
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void RegisterDescriptor()
{
if (!Api.AtLeast11_0())
return;
var cinfo = new XRPlaneSubsystemDescriptor.Cinfo
{
id = "ARKit-Plane",
#if UNITY_2020_2_OR_NEWER
providerType = typeof(ARKitXRPlaneSubsystem.ARKitProvider),
subsystemTypeOverride = typeof(ARKitXRPlaneSubsystem),
#else
subsystemImplementationType = typeof(ARKitXRPlaneSubsystem),
#endif
supportsHorizontalPlaneDetection = true,
supportsVerticalPlaneDetection = Api.AtLeast11_3(),
supportsArbitraryPlaneDetection = false,
supportsBoundaryVertices = true,
supportsClassification = NativeApi.UnityARKit_Planes_SupportsClassification(),
};
XRPlaneSubsystemDescriptor.Create(cinfo);
}
}
}