설명 없음
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.

MinMaxAABB.cs 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. using System;
  2. using System.Runtime.CompilerServices;
  3. using Unity.IL2CPP.CompilerServices;
  4. using static Unity.Mathematics.math;
  5. namespace Unity.Mathematics.Geometry
  6. {
  7. /// <summary>
  8. /// Axis aligned bounding box (AABB) stored in min and max form.
  9. /// </summary>
  10. /// <remarks>
  11. /// Axis aligned bounding boxes (AABB) are boxes where each side is parallel with one of the Cartesian coordinate axes
  12. /// X, Y, and Z. AABBs are useful for approximating the region an object (or collection of objects) occupies and quickly
  13. /// testing whether or not that object (or collection of objects) is relevant. Because they are axis aligned, they
  14. /// are very cheap to construct and perform overlap tests with them.
  15. /// </remarks>
  16. [System.Serializable]
  17. [Il2CppEagerStaticClassConstruction]
  18. internal struct MinMaxAABB : IEquatable<MinMaxAABB>
  19. {
  20. /// <summary>
  21. /// The minimum point contained by the AABB.
  22. /// </summary>
  23. /// <remarks>
  24. /// If any component of <see cref="Min"/> is greater than <see cref="Max"/> then this AABB is invalid.
  25. /// </remarks>
  26. /// <seealso cref="IsValid"/>
  27. public float3 Min;
  28. /// <summary>
  29. /// The maximum point contained by the AABB.
  30. /// </summary>
  31. /// <remarks>
  32. /// If any component of <see cref="Max"/> is less than <see cref="Min"/> then this AABB is invalid.
  33. /// </remarks>
  34. /// <seealso cref="IsValid"/>
  35. public float3 Max;
  36. /// <summary>
  37. /// Constructs the AABB with the given minimum and maximum.
  38. /// </summary>
  39. /// <remarks>
  40. /// If you have a center and extents, you can call <see cref="CreateFromCenterAndExtents"/> or <see cref="CreateFromCenterAndHalfExtents"/>
  41. /// to create the AABB.
  42. /// </remarks>
  43. /// <param name="min">Minimum point inside AABB.</param>
  44. /// <param name="max">Maximum point inside AABB.</param>
  45. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  46. public MinMaxAABB(float3 min, float3 max)
  47. {
  48. Min = min;
  49. Max = max;
  50. }
  51. /// <summary>
  52. /// Creates the AABB from a center and extents.
  53. /// </summary>
  54. /// <remarks>
  55. /// This function takes full extents. It is the distance between <see cref="Min"/> and <see cref="Max"/>.
  56. /// If you have half extents, you can call <see cref="CreateFromCenterAndHalfExtents"/>.
  57. /// </remarks>
  58. /// <param name="center">Center of AABB.</param>
  59. /// <param name="extents">Full extents of AABB.</param>
  60. /// <returns>AABB created from inputs.</returns>
  61. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  62. public static MinMaxAABB CreateFromCenterAndExtents(float3 center, float3 extents)
  63. {
  64. return CreateFromCenterAndHalfExtents(center, extents * 0.5f);
  65. }
  66. /// <summary>
  67. /// Creates the AABB from a center and half extents.
  68. /// </summary>
  69. /// <remarks>
  70. /// This function takes half extents. It is half the distance between <see cref="Min"/> and <see cref="Max"/>.
  71. /// If you have full extents, you can call <see cref="CreateFromCenterAndExtents"/>.
  72. /// </remarks>
  73. /// <param name="center">Center of AABB.</param>
  74. /// <param name="halfExtents">Half extents of AABB.</param>
  75. /// <returns>AABB created from inputs.</returns>
  76. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  77. public static MinMaxAABB CreateFromCenterAndHalfExtents(float3 center, float3 halfExtents)
  78. {
  79. return new MinMaxAABB(center - halfExtents, center + halfExtents);
  80. }
  81. /// <summary>
  82. /// Computes the extents of the AABB.
  83. /// </summary>
  84. /// <remarks>
  85. /// Extents is the componentwise distance between min and max.
  86. /// </remarks>
  87. public float3 Extents => Max - Min;
  88. /// <summary>
  89. /// Computes the half extents of the AABB.
  90. /// </summary>
  91. /// <remarks>
  92. /// HalfExtents is half of the componentwise distance between min and max. Subtracting HalfExtents from Center
  93. /// gives Min and adding HalfExtents to Center gives Max.
  94. /// </remarks>
  95. public float3 HalfExtents => (Max - Min) * 0.5f;
  96. /// <summary>
  97. /// Computes the center of the AABB.
  98. /// </summary>
  99. public float3 Center => (Max + Min) * 0.5f;
  100. /// <summary>
  101. /// Check if the AABB is valid.
  102. /// </summary>
  103. /// <remarks>
  104. /// An AABB is considered valid if <see cref="Min"/> is componentwise less than or equal to <see cref="Max"/>.
  105. /// </remarks>
  106. /// <returns>True if <see cref="Min"/> is componentwise less than or equal to <see cref="Max"/>.</returns>
  107. public bool IsValid => math.all(Min <= Max);
  108. /// <summary>
  109. /// Computes the surface area for this axis aligned bounding box.
  110. /// </summary>
  111. public float SurfaceArea
  112. {
  113. get
  114. {
  115. float3 diff = Max - Min;
  116. return 2 * math.dot(diff, diff.yzx);
  117. }
  118. }
  119. /// <summary>
  120. /// Tests if the input point is contained by the AABB.
  121. /// </summary>
  122. /// <param name="point">Point to test.</param>
  123. /// <returns>True if AABB contains the input point.</returns>
  124. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  125. public bool Contains(float3 point) => math.all(point >= Min & point <= Max);
  126. /// <summary>
  127. /// Tests if the input AABB is contained entirely by this AABB.
  128. /// </summary>
  129. /// <param name="aabb">AABB to test.</param>
  130. /// <returns>True if input AABB is contained entirely by this AABB.</returns>
  131. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  132. public bool Contains(MinMaxAABB aabb) => math.all((Min <= aabb.Min) & (Max >= aabb.Max));
  133. /// <summary>
  134. /// Tests if the input AABB overlaps this AABB.
  135. /// </summary>
  136. /// <param name="aabb">AABB to test.</param>
  137. /// <returns>True if input AABB overlaps with this AABB.</returns>
  138. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  139. public bool Overlaps(MinMaxAABB aabb)
  140. {
  141. return math.all(Max >= aabb.Min & Min <= aabb.Max);
  142. }
  143. /// <summary>
  144. /// Expands the AABB by the given signed distance.
  145. /// </summary>
  146. /// <remarks>
  147. /// Positive distance expands the AABB while negative distance shrinks the AABB.
  148. /// </remarks>
  149. /// <param name="signedDistance">Signed distance to expand the AABB with.</param>
  150. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  151. public void Expand(float signedDistance)
  152. {
  153. Min -= signedDistance;
  154. Max += signedDistance;
  155. }
  156. /// <summary>
  157. /// Encapsulates the given AABB.
  158. /// </summary>
  159. /// <remarks>
  160. /// Modifies this AABB so that it contains the given AABB. If the given AABB is already contained by this AABB,
  161. /// then this AABB doesn't change.
  162. /// </remarks>
  163. /// <seealso cref="Contains(Unity.Mathematics.Geometry.MinMaxAABB)"/>
  164. /// <param name="aabb">AABB to encapsulate.</param>
  165. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  166. public void Encapsulate(MinMaxAABB aabb)
  167. {
  168. Min = math.min(Min, aabb.Min);
  169. Max = math.max(Max, aabb.Max);
  170. }
  171. /// <summary>
  172. /// Encapsulate the given point.
  173. /// </summary>
  174. /// <remarks>
  175. /// Modifies this AABB so that it contains the given point. If the given point is already contained by this AABB,
  176. /// then this AABB doesn't change.
  177. /// </remarks>
  178. /// <seealso cref="Contains(Unity.Mathematics.float3)"/>
  179. /// <param name="point">Point to encapsulate.</param>
  180. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  181. public void Encapsulate(float3 point)
  182. {
  183. Min = math.min(Min, point);
  184. Max = math.max(Max, point);
  185. }
  186. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  187. public bool Equals(MinMaxAABB other)
  188. {
  189. return Min.Equals(other.Min) && Max.Equals(other.Max);
  190. }
  191. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  192. public override string ToString()
  193. {
  194. return string.Format("MinMaxAABB({0}, {1})", Min, Max);
  195. }
  196. }
  197. internal static partial class Math
  198. {
  199. /// <summary>
  200. /// Transforms the AABB with the given transform.
  201. /// </summary>
  202. /// <remarks>
  203. /// The resulting AABB encapsulates the transformed AABB which may not be axis aligned after the transformation.
  204. /// </remarks>
  205. /// <param name="transform">Transform to apply to AABB.</param>
  206. /// <param name="aabb">AABB to be transformed.</param>
  207. /// <returns>Transformed AABB.</returns>
  208. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  209. public static MinMaxAABB Transform(RigidTransform transform, MinMaxAABB aabb)
  210. {
  211. float3 halfExtentsInA = aabb.HalfExtents;
  212. // Rotate each axis individually and find their new positions in the rotated space.
  213. float3 x = math.rotate(transform.rot, new float3(halfExtentsInA.x, 0, 0));
  214. float3 y = math.rotate(transform.rot, new float3(0, halfExtentsInA.y, 0));
  215. float3 z = math.rotate(transform.rot, new float3(0, 0, halfExtentsInA.z));
  216. // Find the new max corner by summing the rotated axes. Absolute value of each axis
  217. // since we are trying to find the max corner.
  218. float3 halfExtentsInB = math.abs(x) + math.abs(y) + math.abs(z);
  219. float3 centerInB = math.transform(transform, aabb.Center);
  220. return new MinMaxAABB(centerInB - halfExtentsInB, centerInB + halfExtentsInB);
  221. }
  222. /// <summary>
  223. /// Transforms the AABB with the given transform.
  224. /// </summary>
  225. /// <remarks>
  226. /// The resulting AABB encapsulates the transformed AABB which may not be axis aligned after the transformation.
  227. /// </remarks>
  228. /// <param name="transform">Transform to apply to AABB.</param>
  229. /// <param name="aabb">AABB to be transformed.</param>
  230. /// <returns>Transformed AABB.</returns>
  231. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  232. public static MinMaxAABB Transform(float4x4 transform, MinMaxAABB aabb)
  233. {
  234. var transformed = Transform(new float3x3(transform), aabb);
  235. transformed.Min += transform.c3.xyz;
  236. transformed.Max += transform.c3.xyz;
  237. return transformed;
  238. }
  239. /// <summary>
  240. /// Transforms the AABB with the given transform.
  241. /// </summary>
  242. /// <remarks>
  243. /// The resulting AABB encapsulates the transformed AABB which may not be axis aligned after the transformation.
  244. /// </remarks>
  245. /// <param name="transform">Transform to apply to AABB.</param>
  246. /// <param name="aabb">AABB to be transformed.</param>
  247. /// <returns>Transformed AABB.</returns>
  248. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  249. public static MinMaxAABB Transform(float3x3 transform, MinMaxAABB aabb)
  250. {
  251. // From Christer Ericson's Real-Time Collision Detection on page 86 and 87.
  252. // We want the transformed minimum and maximums of the AABB. Multiplying a 3x3 matrix on the left of a
  253. // column vector looks like so:
  254. //
  255. // [ c0.x c1.x c2.x ] [ x ] [ c0.x * x + c1.x * y + c2.x * z ]
  256. // [ c0.y c1.y c2.y ] [ y ] = [ c0.y * x + c1.y * y + c2.y * z ]
  257. // [ c0.z c1.z c2.z ] [ z ] [ c0.z * x + c1.z * y + c2.z * z ]
  258. //
  259. // The column vectors we will use are the input AABB's min and max. Simply multiplying those two vectors
  260. // with the transformation matrix won't guarantee we get the new min and max since those are only two
  261. // points out of eight in the AABB and one of the other six may set the new min or max.
  262. //
  263. // To ensure we get the correct min and max, we must transform all eight points. But it's not necessary
  264. // to actually perform eight matrix multiplies to get our final result. Instead, we can build the min and
  265. // max incrementally by computing each term in the above matrix multiply separately then summing the min
  266. // (or max). For instance, to find the new minimum contributed by the original min and max x component, we
  267. // compute this:
  268. //
  269. // newMin.x = min(c0.x * Min.x, c0.x * Max.x);
  270. // newMin.y = min(c0.y * Min.x, c0.y * Max.x);
  271. // newMin.z = min(c0.z * Min.x, c0.z * Max.x);
  272. //
  273. // Then we add minimum contributed by the original min and max y components:
  274. //
  275. // newMin.x += min(c1.x * Min.y, c1.x * Max.y);
  276. // newMin.y += min(c1.y * Min.y, c1.y * Max.y);
  277. // newMin.z += min(c1.z * Min.y, c1.z * Max.y);
  278. //
  279. // And so on. Translation can be handled by simply initializing the new min and max with the translation
  280. // amount since it does not affect the min and max bounds in local space.
  281. var t1 = transform.c0.xyz * aabb.Min.xxx;
  282. var t2 = transform.c0.xyz * aabb.Max.xxx;
  283. var minMask = t1 < t2;
  284. var transformed = new MinMaxAABB(select(t2, t1, minMask), select(t2, t1, !minMask));
  285. t1 = transform.c1.xyz * aabb.Min.yyy;
  286. t2 = transform.c1.xyz * aabb.Max.yyy;
  287. minMask = t1 < t2;
  288. transformed.Min += select(t2, t1, minMask);
  289. transformed.Max += select(t2, t1, !minMask);
  290. t1 = transform.c2.xyz * aabb.Min.zzz;
  291. t2 = transform.c2.xyz * aabb.Max.zzz;
  292. minMask = t1 < t2;
  293. transformed.Min += select(t2, t1, minMask);
  294. transformed.Max += select(t2, t1, !minMask);
  295. return transformed;
  296. }
  297. }
  298. }