SW 중심대학 OSS GIT 서버 박건태, 이승준, 고기완, 이준호 새로운 배포
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

286 lines
11 KiB

4 years ago
  1. using System;
  2. using System.Collections.Generic;
  3. using Unity.Collections;
  4. using UnityEngine.Serialization;
  5. using UnityEngine.XR.ARSubsystems;
  6. namespace UnityEngine.XR.ARFoundation
  7. {
  8. /// <summary>
  9. /// A manager for <see cref="ARPlane"/>s. Creates, updates, and removes
  10. /// <c>GameObject</c>s in response to detected surfaces in the physical
  11. /// environment.
  12. /// </summary>
  13. [DefaultExecutionOrder(ARUpdateOrder.k_PlaneManager)]
  14. [DisallowMultipleComponent]
  15. [RequireComponent(typeof(ARSessionOrigin))]
  16. [HelpURL("https://docs.unity3d.com/Packages/com.unity.xr.arfoundation@3.0/api/UnityEngine.XR.ARFoundation.ARPlaneManager.html")]
  17. public sealed class ARPlaneManager : ARTrackableManager<
  18. XRPlaneSubsystem,
  19. XRPlaneSubsystemDescriptor,
  20. BoundedPlane,
  21. ARPlane>, IRaycaster
  22. {
  23. [SerializeField]
  24. [Tooltip("If not null, instantiates this prefab for each created plane.")]
  25. GameObject m_PlanePrefab;
  26. /// <summary>
  27. /// Getter/setter for the Plane Prefab.
  28. /// </summary>
  29. public GameObject planePrefab
  30. {
  31. get { return m_PlanePrefab; }
  32. set { m_PlanePrefab = value; }
  33. }
  34. [SerializeField, PlaneDetectionModeMask]
  35. [Tooltip("The types of planes to detect.")]
  36. [FormerlySerializedAs("PlaneDetectionFlags")]
  37. PlaneDetectionMode m_DetectionMode = k_PlaneDetectionModeEverything;
  38. /// <summary>
  39. /// Get or set the <c>PlaneDetectionMode</c> to use for plane detection.
  40. /// </summary>
  41. public PlaneDetectionMode detectionMode
  42. {
  43. get
  44. {
  45. if (m_DetectionMode == k_PlaneDetectionModeEverything)
  46. return PlaneDetectionMode.Horizontal | PlaneDetectionMode.Vertical;
  47. return m_DetectionMode;
  48. }
  49. set
  50. {
  51. m_DetectionMode = value;
  52. if (subsystem != null)
  53. subsystem.planeDetectionMode = detectionMode;
  54. }
  55. }
  56. /// <summary>
  57. /// Invoked when planes have changed (been added, updated, or removed).
  58. /// </summary>
  59. public event Action<ARPlanesChangedEventArgs> planesChanged;
  60. /// <summary>
  61. /// Attempt to retrieve an existing <see cref="ARPlane"/> by <paramref name="trackableId"/>.
  62. /// </summary>
  63. /// <param name="trackableId">The <see cref="TrackableId"/> of the plane to retrieve.</param>
  64. /// <returns>The <see cref="ARPlane"/> with <paramref name="trackableId"/>, or <c>null</c> if it does not exist.</returns>
  65. public ARPlane GetPlane(TrackableId trackableId)
  66. {
  67. ARPlane plane;
  68. if (m_Trackables.TryGetValue(trackableId, out plane))
  69. return plane;
  70. return null;
  71. }
  72. /// <summary>
  73. /// Performs a raycast against all currently tracked planes.
  74. /// </summary>
  75. /// <param name="ray">The ray, in Unity world space, to cast.</param>
  76. /// <param name="trackableTypeMask">A mask of raycast types to perform.</param>
  77. /// <param name="allocator">The <c>Allocator</c> to use when creating the returned <c>NativeArray</c>.</param>
  78. /// <returns>
  79. /// A new <c>NativeArray</c> of raycast results allocated with <paramref name="allocator"/>.
  80. /// The caller owns the memory and is responsible for calling <c>Dispose</c> on the <c>NativeArray</c>.
  81. /// </returns>
  82. /// <seealso cref="ARRaycastManager.Raycast(Ray, List{ARRaycastHit}, TrackableType)"/>
  83. /// <seealso cref="ARRaycastManager.Raycast(Vector2, List{ARRaycastHit}, TrackableType)"/>
  84. public NativeArray<XRRaycastHit> Raycast(
  85. Ray ray,
  86. TrackableType trackableTypeMask,
  87. Allocator allocator)
  88. {
  89. // No plane types requested; early out.
  90. if ((trackableTypeMask & TrackableType.Planes) == TrackableType.None)
  91. return new NativeArray<XRRaycastHit>(0, allocator);
  92. var trackableCollection = trackables;
  93. // Allocate a buffer that is at least large enough to contain a hit against every plane
  94. var hitBuffer = new NativeArray<XRRaycastHit>(trackableCollection.count, Allocator.Temp);
  95. try
  96. {
  97. int count = 0;
  98. foreach (var plane in trackableCollection)
  99. {
  100. TrackableType trackableTypes = TrackableType.None;
  101. var normal = plane.transform.localRotation * Vector3.up;
  102. var infinitePlane = new Plane(normal, plane.transform.localPosition);
  103. float distance;
  104. if (!infinitePlane.Raycast(ray, out distance))
  105. continue;
  106. // Pose in session space
  107. var pose = new Pose(
  108. ray.origin + ray.direction * distance,
  109. plane.transform.localRotation);
  110. if ((trackableTypeMask & TrackableType.PlaneWithinInfinity) != TrackableType.None)
  111. trackableTypes |= TrackableType.PlaneWithinInfinity;
  112. // To test the rest, we need the intersection point in plane space
  113. var hitPositionPlaneSpace3d = Quaternion.Inverse(plane.transform.localRotation) * (pose.position - plane.transform.localPosition);
  114. var hitPositionPlaneSpace = new Vector2(hitPositionPlaneSpace3d.x, hitPositionPlaneSpace3d.z);
  115. var estimatedOrWithinBounds = TrackableType.PlaneWithinBounds | TrackableType.PlaneEstimated;
  116. if ((trackableTypeMask & estimatedOrWithinBounds) != TrackableType.None)
  117. {
  118. var differenceFromCenter = hitPositionPlaneSpace - plane.centerInPlaneSpace;
  119. if ((Mathf.Abs(differenceFromCenter.x) <= plane.extents.x) &&
  120. (Mathf.Abs(differenceFromCenter.y) <= plane.extents.y))
  121. {
  122. trackableTypes |= (estimatedOrWithinBounds & trackableTypeMask);
  123. }
  124. }
  125. if ((trackableTypeMask & TrackableType.PlaneWithinPolygon) != TrackableType.None)
  126. {
  127. if (WindingNumber(hitPositionPlaneSpace, plane.boundary) != 0)
  128. trackableTypes |= TrackableType.PlaneWithinPolygon;
  129. }
  130. if (trackableTypes != TrackableType.None)
  131. {
  132. hitBuffer[count++] = new XRRaycastHit(
  133. plane.trackableId,
  134. pose,
  135. distance,
  136. trackableTypes);
  137. }
  138. }
  139. // Finally, copy to return value
  140. var hitResults = new NativeArray<XRRaycastHit>(count, allocator);
  141. NativeArray<XRRaycastHit>.Copy(hitBuffer, hitResults, count);
  142. return hitResults;
  143. }
  144. finally
  145. {
  146. hitBuffer.Dispose();
  147. }
  148. }
  149. static float GetCrossDirection(Vector2 a, Vector2 b)
  150. {
  151. return a.x * b.y - a.y * b.x;
  152. }
  153. // See http://geomalgorithms.com/a03-_inclusion.html
  154. static int WindingNumber(
  155. Vector2 positionInPlaneSpace,
  156. NativeArray<Vector2> boundaryInPlaneSpace)
  157. {
  158. int windingNumber = 0;
  159. Vector2 point = positionInPlaneSpace;
  160. for (int i = 0; i < boundaryInPlaneSpace.Length; ++i)
  161. {
  162. int j = (i + 1) % boundaryInPlaneSpace.Length;
  163. Vector2 vi = boundaryInPlaneSpace[i];
  164. Vector2 vj = boundaryInPlaneSpace[j];
  165. if (vi.y <= point.y)
  166. {
  167. if (vj.y > point.y) // an upward crossing
  168. {
  169. if (GetCrossDirection(vj - vi, point - vi) < 0f) // P left of edge
  170. ++windingNumber;
  171. }
  172. // have a valid up intersect
  173. }
  174. else
  175. { // y > P.y (no test needed)
  176. if (vj.y <= point.y) // a downward crossing
  177. {
  178. if (GetCrossDirection(vj - vi, point - vi) > 0f) // P right of edge
  179. --windingNumber;
  180. }
  181. // have a valid down intersect
  182. }
  183. }
  184. return windingNumber;
  185. }
  186. protected override GameObject GetPrefab()
  187. {
  188. return m_PlanePrefab;
  189. }
  190. protected override void OnBeforeStart()
  191. {
  192. subsystem.planeDetectionMode = detectionMode;
  193. }
  194. protected override void OnAfterSetSessionRelativeData(
  195. ARPlane plane,
  196. BoundedPlane sessionRelativeData)
  197. {
  198. ARPlane subsumedByPlane;
  199. if (m_Trackables.TryGetValue(sessionRelativeData.subsumedById, out subsumedByPlane))
  200. {
  201. plane.subsumedBy = subsumedByPlane;
  202. }
  203. else
  204. {
  205. plane.subsumedBy = null;
  206. }
  207. plane.UpdateBoundary(subsystem);
  208. }
  209. protected override void OnTrackablesChanged(
  210. List<ARPlane> added,
  211. List<ARPlane> updated,
  212. List<ARPlane> removed)
  213. {
  214. if (planesChanged != null)
  215. {
  216. planesChanged(
  217. new ARPlanesChangedEventArgs(
  218. added,
  219. updated,
  220. removed));
  221. }
  222. }
  223. /// <summary>
  224. /// The name to be used for the <c>GameObject</c> whenever a new plane is detected.
  225. /// </summary>
  226. protected override string gameObjectName
  227. {
  228. get { return "ARPlane"; }
  229. }
  230. protected override void OnEnable()
  231. {
  232. base.OnEnable();
  233. if (subsystem != null)
  234. {
  235. var raycastManager = GetComponent<ARRaycastManager>();
  236. if (raycastManager != null)
  237. raycastManager.RegisterRaycaster(this);
  238. }
  239. }
  240. protected override void OnDisable()
  241. {
  242. base.OnDisable();
  243. var raycastManager = GetComponent<ARRaycastManager>();
  244. if (raycastManager != null)
  245. raycastManager.UnregisterRaycaster(this);
  246. }
  247. static List<Vector2> s_PlaneSpaceBoundary = new List<Vector2>();
  248. const PlaneDetectionMode k_PlaneDetectionModeEverything = (PlaneDetectionMode)(-1);
  249. }
  250. }