AABox.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <Jolt/Geometry/Triangle.h>
  5. #include <Jolt/Geometry/IndexedTriangle.h>
  6. #include <Jolt/Geometry/Plane.h>
  7. #include <Jolt/Math/Mat44.h>
  8. JPH_NAMESPACE_BEGIN
  9. /// Axis aligned box
  10. class [[nodiscard]] AABox
  11. {
  12. public:
  13. JPH_OVERRIDE_NEW_DELETE
  14. /// Constructor
  15. AABox() : mMin(Vec3::sReplicate(FLT_MAX)), mMax(Vec3::sReplicate(-FLT_MAX)) { }
  16. AABox(Vec3Arg inMin, Vec3Arg inMax) : mMin(inMin), mMax(inMax) { }
  17. AABox(DVec3Arg inMin, DVec3Arg inMax) : mMin(inMin.ToVec3RoundDown()), mMax(inMax.ToVec3RoundUp()) { }
  18. AABox(Vec3Arg inCenter, float inRadius) : mMin(inCenter - Vec3::sReplicate(inRadius)), mMax(inCenter + Vec3::sReplicate(inRadius)) { }
  19. /// Create box from 2 points
  20. static AABox sFromTwoPoints(Vec3Arg inP1, Vec3Arg inP2) { return AABox(Vec3::sMin(inP1, inP2), Vec3::sMax(inP1, inP2)); }
  21. /// Get bounding box of size 2 * FLT_MAX
  22. static AABox sBiggest()
  23. {
  24. return AABox(Vec3::sReplicate(-FLT_MAX), Vec3::sReplicate(FLT_MAX));
  25. }
  26. /// Comparison operators
  27. bool operator == (const AABox &inRHS) const { return mMin == inRHS.mMin && mMax == inRHS.mMax; }
  28. bool operator != (const AABox &inRHS) const { return mMin != inRHS.mMin || mMax != inRHS.mMax; }
  29. /// Reset the bounding box to an empty bounding box
  30. void SetEmpty()
  31. {
  32. mMin = Vec3::sReplicate(FLT_MAX);
  33. mMax = Vec3::sReplicate(-FLT_MAX);
  34. }
  35. /// Check if the bounding box is valid (max >= min)
  36. bool IsValid() const
  37. {
  38. return mMin.GetX() <= mMax.GetX() && mMin.GetY() <= mMax.GetY() && mMin.GetZ() <= mMax.GetZ();
  39. }
  40. /// Encapsulate point in bounding box
  41. void Encapsulate(Vec3Arg inPos)
  42. {
  43. mMin = Vec3::sMin(mMin, inPos);
  44. mMax = Vec3::sMax(mMax, inPos);
  45. }
  46. /// Encapsulate bounding box in bounding box
  47. void Encapsulate(const AABox &inRHS)
  48. {
  49. mMin = Vec3::sMin(mMin, inRHS.mMin);
  50. mMax = Vec3::sMax(mMax, inRHS.mMax);
  51. }
  52. /// Encapsulate triangle in bounding box
  53. void Encapsulate(const Triangle &inRHS)
  54. {
  55. Vec3 v = Vec3::sLoadFloat3Unsafe(inRHS.mV[0]);
  56. Encapsulate(v);
  57. v = Vec3::sLoadFloat3Unsafe(inRHS.mV[1]);
  58. Encapsulate(v);
  59. v = Vec3::sLoadFloat3Unsafe(inRHS.mV[2]);
  60. Encapsulate(v);
  61. }
  62. /// Encapsulate triangle in bounding box
  63. void Encapsulate(const VertexList &inVertices, const IndexedTriangle &inTriangle)
  64. {
  65. for (uint32 idx : inTriangle.mIdx)
  66. Encapsulate(Vec3(inVertices[idx]));
  67. }
  68. /// Intersect this bounding box with inOther, returns the intersection
  69. AABox Intersect(const AABox &inOther) const
  70. {
  71. return AABox(Vec3::sMax(mMin, inOther.mMin), Vec3::sMin(mMax, inOther.mMax));
  72. }
  73. /// Make sure that each edge of the bounding box has a minimal length
  74. void EnsureMinimalEdgeLength(float inMinEdgeLength)
  75. {
  76. Vec3 min_length = Vec3::sReplicate(inMinEdgeLength);
  77. mMax = Vec3::sSelect(mMax, mMin + min_length, Vec3::sLess(mMax - mMin, min_length));
  78. }
  79. /// Widen the box on both sides by inVector
  80. void ExpandBy(Vec3Arg inVector)
  81. {
  82. mMin -= inVector;
  83. mMax += inVector;
  84. }
  85. /// Get center of bounding box
  86. Vec3 GetCenter() const
  87. {
  88. return 0.5f * (mMin + mMax);
  89. }
  90. /// Get extent of bounding box (half of the size)
  91. Vec3 GetExtent() const
  92. {
  93. return 0.5f * (mMax - mMin);
  94. }
  95. /// Get size of bounding box
  96. Vec3 GetSize() const
  97. {
  98. return mMax - mMin;
  99. }
  100. /// Get surface area of bounding box
  101. float GetSurfaceArea() const
  102. {
  103. Vec3 extent = mMax - mMin;
  104. return 2.0f * (extent.GetX() * extent.GetY() + extent.GetX() * extent.GetZ() + extent.GetY() * extent.GetZ());
  105. }
  106. /// Get volume of bounding box
  107. float GetVolume() const
  108. {
  109. Vec3 extent = mMax - mMin;
  110. return extent.GetX() * extent.GetY() * extent.GetZ();
  111. }
  112. /// Check if this box contains another box
  113. bool Contains(const AABox &inOther) const
  114. {
  115. return UVec4::sAnd(Vec3::sLessOrEqual(mMin, inOther.mMin), Vec3::sGreaterOrEqual(mMax, inOther.mMax)).TestAllXYZTrue();
  116. }
  117. /// Check if this box contains a point
  118. bool Contains(Vec3Arg inOther) const
  119. {
  120. return UVec4::sAnd(Vec3::sLessOrEqual(mMin, inOther), Vec3::sGreaterOrEqual(mMax, inOther)).TestAllXYZTrue();
  121. }
  122. /// Check if this box contains a point
  123. bool Contains(DVec3Arg inOther) const
  124. {
  125. return Contains(Vec3(inOther));
  126. }
  127. /// Check if this box overlaps with another box
  128. bool Overlaps(const AABox &inOther) const
  129. {
  130. return !UVec4::sOr(Vec3::sGreater(mMin, inOther.mMax), Vec3::sLess(mMax, inOther.mMin)).TestAnyXYZTrue();
  131. }
  132. /// Check if this box overlaps with a plane
  133. bool Overlaps(const Plane &inPlane) const
  134. {
  135. Vec3 normal = inPlane.GetNormal();
  136. float dist_normal = inPlane.SignedDistance(GetSupport(normal));
  137. float dist_min_normal = inPlane.SignedDistance(GetSupport(-normal));
  138. return dist_normal * dist_min_normal <= 0.0f; // If both support points are on the same side of the plane we don't overlap
  139. }
  140. /// Translate bounding box
  141. void Translate(Vec3Arg inTranslation)
  142. {
  143. mMin += inTranslation;
  144. mMax += inTranslation;
  145. }
  146. /// Translate bounding box
  147. void Translate(DVec3Arg inTranslation)
  148. {
  149. mMin = (DVec3(mMin) + inTranslation).ToVec3RoundDown();
  150. mMax = (DVec3(mMax) + inTranslation).ToVec3RoundUp();
  151. }
  152. /// Transform bounding box
  153. AABox Transformed(Mat44Arg inMatrix) const
  154. {
  155. // Start with the translation of the matrix
  156. Vec3 new_min, new_max;
  157. new_min = new_max = inMatrix.GetTranslation();
  158. // Now find the extreme points by considering the product of the min and max with each column of inMatrix
  159. for (int c = 0; c < 3; ++c)
  160. {
  161. Vec3 col = inMatrix.GetColumn3(c);
  162. Vec3 a = col * mMin[c];
  163. Vec3 b = col * mMax[c];
  164. new_min += Vec3::sMin(a, b);
  165. new_max += Vec3::sMax(a, b);
  166. }
  167. // Return the new bounding box
  168. return AABox(new_min, new_max);
  169. }
  170. /// Transform bounding box
  171. AABox Transformed(DMat44Arg inMatrix) const
  172. {
  173. AABox transformed = Transformed(inMatrix.GetRotation());
  174. transformed.Translate(inMatrix.GetTranslation());
  175. return transformed;
  176. }
  177. /// Scale this bounding box, can handle non-uniform and negative scaling
  178. AABox Scaled(Vec3Arg inScale) const
  179. {
  180. return AABox::sFromTwoPoints(mMin * inScale, mMax * inScale);
  181. }
  182. /// Calculate the support vector for this convex shape.
  183. Vec3 GetSupport(Vec3Arg inDirection) const
  184. {
  185. return Vec3::sSelect(mMax, mMin, Vec3::sLess(inDirection, Vec3::sZero()));
  186. }
  187. /// Get the vertices of the face that faces inDirection the most
  188. template <class VERTEX_ARRAY>
  189. void GetSupportingFace(Vec3Arg inDirection, VERTEX_ARRAY &outVertices) const
  190. {
  191. outVertices.resize(4);
  192. int axis = inDirection.Abs().GetHighestComponentIndex();
  193. if (inDirection[axis] < 0.0f)
  194. {
  195. switch (axis)
  196. {
  197. case 0:
  198. outVertices[0] = Vec3(mMax.GetX(), mMin.GetY(), mMin.GetZ());
  199. outVertices[1] = Vec3(mMax.GetX(), mMax.GetY(), mMin.GetZ());
  200. outVertices[2] = Vec3(mMax.GetX(), mMax.GetY(), mMax.GetZ());
  201. outVertices[3] = Vec3(mMax.GetX(), mMin.GetY(), mMax.GetZ());
  202. break;
  203. case 1:
  204. outVertices[0] = Vec3(mMin.GetX(), mMax.GetY(), mMin.GetZ());
  205. outVertices[1] = Vec3(mMin.GetX(), mMax.GetY(), mMax.GetZ());
  206. outVertices[2] = Vec3(mMax.GetX(), mMax.GetY(), mMax.GetZ());
  207. outVertices[3] = Vec3(mMax.GetX(), mMax.GetY(), mMin.GetZ());
  208. break;
  209. case 2:
  210. outVertices[0] = Vec3(mMin.GetX(), mMin.GetY(), mMax.GetZ());
  211. outVertices[1] = Vec3(mMax.GetX(), mMin.GetY(), mMax.GetZ());
  212. outVertices[2] = Vec3(mMax.GetX(), mMax.GetY(), mMax.GetZ());
  213. outVertices[3] = Vec3(mMin.GetX(), mMax.GetY(), mMax.GetZ());
  214. break;
  215. }
  216. }
  217. else
  218. {
  219. switch (axis)
  220. {
  221. case 0:
  222. outVertices[0] = Vec3(mMin.GetX(), mMin.GetY(), mMin.GetZ());
  223. outVertices[1] = Vec3(mMin.GetX(), mMin.GetY(), mMax.GetZ());
  224. outVertices[2] = Vec3(mMin.GetX(), mMax.GetY(), mMax.GetZ());
  225. outVertices[3] = Vec3(mMin.GetX(), mMax.GetY(), mMin.GetZ());
  226. break;
  227. case 1:
  228. outVertices[0] = Vec3(mMin.GetX(), mMin.GetY(), mMin.GetZ());
  229. outVertices[1] = Vec3(mMax.GetX(), mMin.GetY(), mMin.GetZ());
  230. outVertices[2] = Vec3(mMax.GetX(), mMin.GetY(), mMax.GetZ());
  231. outVertices[3] = Vec3(mMin.GetX(), mMin.GetY(), mMax.GetZ());
  232. break;
  233. case 2:
  234. outVertices[0] = Vec3(mMin.GetX(), mMin.GetY(), mMin.GetZ());
  235. outVertices[1] = Vec3(mMin.GetX(), mMax.GetY(), mMin.GetZ());
  236. outVertices[2] = Vec3(mMax.GetX(), mMax.GetY(), mMin.GetZ());
  237. outVertices[3] = Vec3(mMax.GetX(), mMin.GetY(), mMin.GetZ());
  238. break;
  239. }
  240. }
  241. }
  242. /// Get the closest point on or in this box to inPoint
  243. Vec3 GetClosestPoint(Vec3Arg inPoint) const
  244. {
  245. return Vec3::sMin(Vec3::sMax(inPoint, mMin), mMax);
  246. }
  247. /// Get the squared distance between inPoint and this box (will be 0 if in Point is inside the box)
  248. inline float GetSqDistanceTo(Vec3Arg inPoint) const
  249. {
  250. return (GetClosestPoint(inPoint) - inPoint).LengthSq();
  251. }
  252. /// Bounding box min and max
  253. Vec3 mMin;
  254. Vec3 mMax;
  255. };
  256. JPH_NAMESPACE_END