AABox4.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. #include <Jolt/Geometry/OrientedBox.h>
  6. JPH_NAMESPACE_BEGIN
  7. /// Helper functions that process 4 axis aligned boxes at the same time using SIMD
  8. /// Test if 4 bounding boxes overlap with 1 bounding box, splat 1 box
  9. JPH_INLINE UVec4 AABox4VsBox(const AABox &inBox1, Vec4Arg inBox2MinX, Vec4Arg inBox2MinY, Vec4Arg inBox2MinZ, Vec4Arg inBox2MaxX, Vec4Arg inBox2MaxY, Vec4Arg inBox2MaxZ)
  10. {
  11. // Splat values of box 1
  12. Vec4 box1_minx = inBox1.mMin.SplatX();
  13. Vec4 box1_miny = inBox1.mMin.SplatY();
  14. Vec4 box1_minz = inBox1.mMin.SplatZ();
  15. Vec4 box1_maxx = inBox1.mMax.SplatX();
  16. Vec4 box1_maxy = inBox1.mMax.SplatY();
  17. Vec4 box1_maxz = inBox1.mMax.SplatZ();
  18. // Test separation over each axis
  19. UVec4 nooverlapx = UVec4::sOr(Vec4::sGreater(box1_minx, inBox2MaxX), Vec4::sGreater(inBox2MinX, box1_maxx));
  20. UVec4 nooverlapy = UVec4::sOr(Vec4::sGreater(box1_miny, inBox2MaxY), Vec4::sGreater(inBox2MinY, box1_maxy));
  21. UVec4 nooverlapz = UVec4::sOr(Vec4::sGreater(box1_minz, inBox2MaxZ), Vec4::sGreater(inBox2MinZ, box1_maxz));
  22. // Return overlap
  23. return UVec4::sNot(UVec4::sOr(UVec4::sOr(nooverlapx, nooverlapy), nooverlapz));
  24. }
  25. /// Scale 4 axis aligned boxes
  26. JPH_INLINE void AABox4Scale(Vec3Arg inScale, Vec4Arg inBoxMinX, Vec4Arg inBoxMinY, Vec4Arg inBoxMinZ, Vec4Arg inBoxMaxX, Vec4Arg inBoxMaxY, Vec4Arg inBoxMaxZ, Vec4 &outBoundsMinX, Vec4 &outBoundsMinY, Vec4 &outBoundsMinZ, Vec4 &outBoundsMaxX, Vec4 &outBoundsMaxY, Vec4 &outBoundsMaxZ)
  27. {
  28. Vec4 scale_x = inScale.SplatX();
  29. Vec4 scaled_min_x = scale_x * inBoxMinX;
  30. Vec4 scaled_max_x = scale_x * inBoxMaxX;
  31. outBoundsMinX = Vec4::sMin(scaled_min_x, scaled_max_x); // Negative scale can flip min and max
  32. outBoundsMaxX = Vec4::sMax(scaled_min_x, scaled_max_x);
  33. Vec4 scale_y = inScale.SplatY();
  34. Vec4 scaled_min_y = scale_y * inBoxMinY;
  35. Vec4 scaled_max_y = scale_y * inBoxMaxY;
  36. outBoundsMinY = Vec4::sMin(scaled_min_y, scaled_max_y);
  37. outBoundsMaxY = Vec4::sMax(scaled_min_y, scaled_max_y);
  38. Vec4 scale_z = inScale.SplatZ();
  39. Vec4 scaled_min_z = scale_z * inBoxMinZ;
  40. Vec4 scaled_max_z = scale_z * inBoxMaxZ;
  41. outBoundsMinZ = Vec4::sMin(scaled_min_z, scaled_max_z);
  42. outBoundsMaxZ = Vec4::sMax(scaled_min_z, scaled_max_z);
  43. }
  44. /// Enlarge 4 bounding boxes with extent (add to both sides)
  45. JPH_INLINE void AABox4EnlargeWithExtent(Vec3Arg inExtent, Vec4 &ioBoundsMinX, Vec4 &ioBoundsMinY, Vec4 &ioBoundsMinZ, Vec4 &ioBoundsMaxX, Vec4 &ioBoundsMaxY, Vec4 &ioBoundsMaxZ)
  46. {
  47. Vec4 extent_x = inExtent.SplatX();
  48. ioBoundsMinX -= extent_x;
  49. ioBoundsMaxX += extent_x;
  50. Vec4 extent_y = inExtent.SplatY();
  51. ioBoundsMinY -= extent_y;
  52. ioBoundsMaxY += extent_y;
  53. Vec4 extent_z = inExtent.SplatZ();
  54. ioBoundsMinZ -= extent_z;
  55. ioBoundsMaxZ += extent_z;
  56. }
  57. /// Test if 4 bounding boxes overlap with a point
  58. JPH_INLINE UVec4 AABox4VsPoint(Vec3Arg inPoint, Vec4Arg inBoxMinX, Vec4Arg inBoxMinY, Vec4Arg inBoxMinZ, Vec4Arg inBoxMaxX, Vec4Arg inBoxMaxY, Vec4Arg inBoxMaxZ)
  59. {
  60. // Splat point to 4 component vectors
  61. Vec4 point_x = Vec4(inPoint).SplatX();
  62. Vec4 point_y = Vec4(inPoint).SplatY();
  63. Vec4 point_z = Vec4(inPoint).SplatZ();
  64. // Test if point overlaps with box
  65. UVec4 overlapx = UVec4::sAnd(Vec4::sGreaterOrEqual(point_x, inBoxMinX), Vec4::sLessOrEqual(point_x, inBoxMaxX));
  66. UVec4 overlapy = UVec4::sAnd(Vec4::sGreaterOrEqual(point_y, inBoxMinY), Vec4::sLessOrEqual(point_y, inBoxMaxY));
  67. UVec4 overlapz = UVec4::sAnd(Vec4::sGreaterOrEqual(point_z, inBoxMinZ), Vec4::sLessOrEqual(point_z, inBoxMaxZ));
  68. // Test if all are overlapping
  69. return UVec4::sAnd(UVec4::sAnd(overlapx, overlapy), overlapz);
  70. }
  71. /// Test if 4 bounding boxes overlap with an oriented box
  72. JPH_INLINE UVec4 AABox4VsBox(Mat44Arg inOrientation, Vec3Arg inHalfExtents, Vec4Arg inBoxMinX, Vec4Arg inBoxMinY, Vec4Arg inBoxMinZ, Vec4Arg inBoxMaxX, Vec4Arg inBoxMaxY, Vec4Arg inBoxMaxZ, float inEpsilon = 1.0e-6f)
  73. {
  74. // Taken from: Real Time Collision Detection - Christer Ericson
  75. // Chapter 4.4.1, page 103-105.
  76. // Note that the code is swapped around: A is the aabox and B is the oriented box (this saves us from having to invert the orientation of the oriented box)
  77. // Compute translation vector t (the translation of B in the space of A)
  78. Vec4 t[3] {
  79. inOrientation.GetTranslation().SplatX() - 0.5f * (inBoxMinX + inBoxMaxX),
  80. inOrientation.GetTranslation().SplatY() - 0.5f * (inBoxMinY + inBoxMaxY),
  81. inOrientation.GetTranslation().SplatZ() - 0.5f * (inBoxMinZ + inBoxMaxZ) };
  82. // Compute common subexpressions. Add in an epsilon term to
  83. // counteract arithmetic errors when two edges are parallel and
  84. // their cross product is (near) null (see text for details)
  85. Vec3 epsilon = Vec3::sReplicate(inEpsilon);
  86. Vec3 abs_r[3] { inOrientation.GetAxisX().Abs() + epsilon, inOrientation.GetAxisY().Abs() + epsilon, inOrientation.GetAxisZ().Abs() + epsilon };
  87. // Half extents for a
  88. Vec4 a_half_extents[3] {
  89. 0.5f * (inBoxMaxX - inBoxMinX),
  90. 0.5f * (inBoxMaxY - inBoxMinY),
  91. 0.5f * (inBoxMaxZ - inBoxMinZ) };
  92. // Half extents of b
  93. Vec4 b_half_extents_x = inHalfExtents.SplatX();
  94. Vec4 b_half_extents_y = inHalfExtents.SplatY();
  95. Vec4 b_half_extents_z = inHalfExtents.SplatZ();
  96. // Each component corresponds to 1 overlapping OBB vs ABB
  97. UVec4 overlaps = UVec4(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
  98. // Test axes L = A0, L = A1, L = A2
  99. Vec4 ra, rb;
  100. for (int i = 0; i < 3; i++)
  101. {
  102. ra = a_half_extents[i];
  103. rb = b_half_extents_x * abs_r[0][i] + b_half_extents_y * abs_r[1][i] + b_half_extents_z * abs_r[2][i];
  104. overlaps = UVec4::sAnd(overlaps, Vec4::sLessOrEqual(t[i].Abs(), ra + rb));
  105. }
  106. // Test axes L = B0, L = B1, L = B2
  107. for (int i = 0; i < 3; i++)
  108. {
  109. ra = a_half_extents[0] * abs_r[i][0] + a_half_extents[1] * abs_r[i][1] + a_half_extents[2] * abs_r[i][2];
  110. rb = Vec4::sReplicate(inHalfExtents[i]);
  111. overlaps = UVec4::sAnd(overlaps, Vec4::sLessOrEqual((t[0] * inOrientation(0, i) + t[1] * inOrientation(1, i) + t[2] * inOrientation(2, i)).Abs(), ra + rb));
  112. }
  113. // Test axis L = A0 x B0
  114. ra = a_half_extents[1] * abs_r[0][2] + a_half_extents[2] * abs_r[0][1];
  115. rb = b_half_extents_y * abs_r[2][0] + b_half_extents_z * abs_r[1][0];
  116. overlaps = UVec4::sAnd(overlaps, Vec4::sLessOrEqual((t[2] * inOrientation(1, 0) - t[1] * inOrientation(2, 0)).Abs(), ra + rb));
  117. // Test axis L = A0 x B1
  118. ra = a_half_extents[1] * abs_r[1][2] + a_half_extents[2] * abs_r[1][1];
  119. rb = b_half_extents_x * abs_r[2][0] + b_half_extents_z * abs_r[0][0];
  120. overlaps = UVec4::sAnd(overlaps, Vec4::sLessOrEqual((t[2] * inOrientation(1, 1) - t[1] * inOrientation(2, 1)).Abs(), ra + rb));
  121. // Test axis L = A0 x B2
  122. ra = a_half_extents[1] * abs_r[2][2] + a_half_extents[2] * abs_r[2][1];
  123. rb = b_half_extents_x * abs_r[1][0] + b_half_extents_y * abs_r[0][0];
  124. overlaps = UVec4::sAnd(overlaps, Vec4::sLessOrEqual((t[2] * inOrientation(1, 2) - t[1] * inOrientation(2, 2)).Abs(), ra + rb));
  125. // Test axis L = A1 x B0
  126. ra = a_half_extents[0] * abs_r[0][2] + a_half_extents[2] * abs_r[0][0];
  127. rb = b_half_extents_y * abs_r[2][1] + b_half_extents_z * abs_r[1][1];
  128. overlaps = UVec4::sAnd(overlaps, Vec4::sLessOrEqual((t[0] * inOrientation(2, 0) - t[2] * inOrientation(0, 0)).Abs(), ra + rb));
  129. // Test axis L = A1 x B1
  130. ra = a_half_extents[0] * abs_r[1][2] + a_half_extents[2] * abs_r[1][0];
  131. rb = b_half_extents_x * abs_r[2][1] + b_half_extents_z * abs_r[0][1];
  132. overlaps = UVec4::sAnd(overlaps, Vec4::sLessOrEqual((t[0] * inOrientation(2, 1) - t[2] * inOrientation(0, 1)).Abs(), ra + rb));
  133. // Test axis L = A1 x B2
  134. ra = a_half_extents[0] * abs_r[2][2] + a_half_extents[2] * abs_r[2][0];
  135. rb = b_half_extents_x * abs_r[1][1] + b_half_extents_y * abs_r[0][1];
  136. overlaps = UVec4::sAnd(overlaps, Vec4::sLessOrEqual((t[0] * inOrientation(2, 2) - t[2] * inOrientation(0, 2)).Abs(), ra + rb));
  137. // Test axis L = A2 x B0
  138. ra = a_half_extents[0] * abs_r[0][1] + a_half_extents[1] * abs_r[0][0];
  139. rb = b_half_extents_y * abs_r[2][2] + b_half_extents_z * abs_r[1][2];
  140. overlaps = UVec4::sAnd(overlaps, Vec4::sLessOrEqual((t[1] * inOrientation(0, 0) - t[0] * inOrientation(1, 0)).Abs(), ra + rb));
  141. // Test axis L = A2 x B1
  142. ra = a_half_extents[0] * abs_r[1][1] + a_half_extents[1] * abs_r[1][0];
  143. rb = b_half_extents_x * abs_r[2][2] + b_half_extents_z * abs_r[0][2];
  144. overlaps = UVec4::sAnd(overlaps, Vec4::sLessOrEqual((t[1] * inOrientation(0, 1) - t[0] * inOrientation(1, 1)).Abs(), ra + rb));
  145. // Test axis L = A2 x B2
  146. ra = a_half_extents[0] * abs_r[2][1] + a_half_extents[1] * abs_r[2][0];
  147. rb = b_half_extents_x * abs_r[1][2] + b_half_extents_y * abs_r[0][2];
  148. overlaps = UVec4::sAnd(overlaps, Vec4::sLessOrEqual((t[1] * inOrientation(0, 2) - t[0] * inOrientation(1, 2)).Abs(), ra + rb));
  149. // Return if the OBB vs AABBs are intersecting
  150. return overlaps;
  151. }
  152. /// Convenience function that tests 4 AABoxes vs OrientedBox
  153. JPH_INLINE UVec4 AABox4VsBox(const OrientedBox &inBox, Vec4Arg inBoxMinX, Vec4Arg inBoxMinY, Vec4Arg inBoxMinZ, Vec4Arg inBoxMaxX, Vec4Arg inBoxMaxY, Vec4Arg inBoxMaxZ, float inEpsilon = 1.0e-6f)
  154. {
  155. return AABox4VsBox(inBox.mOrientation, inBox.mHalfExtents, inBoxMinX, inBoxMinY, inBoxMinZ, inBoxMaxX, inBoxMaxY, inBoxMaxZ, inEpsilon);
  156. }
  157. /// Test 4 AABoxes vs a sphere
  158. JPH_INLINE UVec4 AABox4VsSphere(Vec4Arg inCenterX, Vec4Arg inCenterY, Vec4Arg inCenterZ, Vec4Arg inRadiusSq, Vec4Arg inBoxMinX, Vec4Arg inBoxMinY, Vec4Arg inBoxMinZ, Vec4Arg inBoxMaxX, Vec4Arg inBoxMaxY, Vec4Arg inBoxMaxZ)
  159. {
  160. // Get closest point on box
  161. Vec4 closest_x = Vec4::sMin(Vec4::sMax(inCenterX, inBoxMinX), inBoxMaxX);
  162. Vec4 closest_y = Vec4::sMin(Vec4::sMax(inCenterY, inBoxMinY), inBoxMaxY);
  163. Vec4 closest_z = Vec4::sMin(Vec4::sMax(inCenterZ, inBoxMinZ), inBoxMaxZ);
  164. // Test the distance from the center of the sphere to the box is smaller than the radius
  165. Vec4 distance_sq = Square(closest_x - inCenterX) + Square(closest_y - inCenterY) + Square(closest_z - inCenterZ);
  166. return Vec4::sLessOrEqual(distance_sq, inRadiusSq);
  167. }
  168. /// Test 4 AABoxes vs a sphere
  169. JPH_INLINE UVec4 AABox4VsSphere(Vec3Arg inCenter, float inRadiusSq, Vec4Arg inBoxMinX, Vec4Arg inBoxMinY, Vec4Arg inBoxMinZ, Vec4Arg inBoxMaxX, Vec4Arg inBoxMaxY, Vec4Arg inBoxMaxZ)
  170. {
  171. return AABox4VsSphere(inCenter.SplatX(), inCenter.SplatY(), inCenter.SplatZ(), Vec4::sReplicate(inRadiusSq), inBoxMinX, inBoxMinY, inBoxMinZ, inBoxMaxX, inBoxMaxY, inBoxMaxZ);
  172. }
  173. JPH_NAMESPACE_END