OrientedBox.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <Jolt/Jolt.h>
  5. #include <Jolt/Geometry/AABox.h>
  6. #include <Jolt/Geometry/OrientedBox.h>
  7. JPH_NAMESPACE_BEGIN
  8. bool OrientedBox::Overlaps(const AABox &inBox, float inEpsilon) const
  9. {
  10. // Taken from: Real Time Collision Detection - Christer Ericson
  11. // Chapter 4.4.1, page 103-105.
  12. // 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)
  13. // Convert AABox to center / extent representation
  14. Vec3 a_center = inBox.GetCenter();
  15. Vec3 a_half_extents = inBox.GetExtent();
  16. // Compute rotation matrix expressing b in a's coordinate frame
  17. Mat44 rot(mOrientation.GetColumn4(0), mOrientation.GetColumn4(1), mOrientation.GetColumn4(2), mOrientation.GetColumn4(3) - Vec4(a_center, 0));
  18. // Compute common subexpressions. Add in an epsilon term to
  19. // counteract arithmetic errors when two edges are parallel and
  20. // their cross product is (near) null (see text for details)
  21. Vec3 epsilon = Vec3::sReplicate(inEpsilon);
  22. Vec3 abs_r[3] { rot.GetAxisX().Abs() + epsilon, rot.GetAxisY().Abs() + epsilon, rot.GetAxisZ().Abs() + epsilon };
  23. // Test axes L = A0, L = A1, L = A2
  24. float ra, rb;
  25. for (int i = 0; i < 3; i++)
  26. {
  27. ra = a_half_extents[i];
  28. rb = mHalfExtents[0] * abs_r[0][i] + mHalfExtents[1] * abs_r[1][i] + mHalfExtents[2] * abs_r[2][i];
  29. if (abs(rot(i, 3)) > ra + rb) return false;
  30. }
  31. // Test axes L = B0, L = B1, L = B2
  32. for (int i = 0; i < 3; i++)
  33. {
  34. ra = a_half_extents.Dot(abs_r[i]);
  35. rb = mHalfExtents[i];
  36. if (abs(rot.GetTranslation().Dot(rot.GetColumn3(i))) > ra + rb) return false;
  37. }
  38. // Test axis L = A0 x B0
  39. ra = a_half_extents[1] * abs_r[0][2] + a_half_extents[2] * abs_r[0][1];
  40. rb = mHalfExtents[1] * abs_r[2][0] + mHalfExtents[2] * abs_r[1][0];
  41. if (abs(rot(2, 3) * rot(1, 0) - rot(1, 3) * rot(2, 0)) > ra + rb) return false;
  42. // Test axis L = A0 x B1
  43. ra = a_half_extents[1] * abs_r[1][2] + a_half_extents[2] * abs_r[1][1];
  44. rb = mHalfExtents[0] * abs_r[2][0] + mHalfExtents[2] * abs_r[0][0];
  45. if (abs(rot(2, 3) * rot(1, 1) - rot(1, 3) * rot(2, 1)) > ra + rb) return false;
  46. // Test axis L = A0 x B2
  47. ra = a_half_extents[1] * abs_r[2][2] + a_half_extents[2] * abs_r[2][1];
  48. rb = mHalfExtents[0] * abs_r[1][0] + mHalfExtents[1] * abs_r[0][0];
  49. if (abs(rot(2, 3) * rot(1, 2) - rot(1, 3) * rot(2, 2)) > ra + rb) return false;
  50. // Test axis L = A1 x B0
  51. ra = a_half_extents[0] * abs_r[0][2] + a_half_extents[2] * abs_r[0][0];
  52. rb = mHalfExtents[1] * abs_r[2][1] + mHalfExtents[2] * abs_r[1][1];
  53. if (abs(rot(0, 3) * rot(2, 0) - rot(2, 3) * rot(0, 0)) > ra + rb) return false;
  54. // Test axis L = A1 x B1
  55. ra = a_half_extents[0] * abs_r[1][2] + a_half_extents[2] * abs_r[1][0];
  56. rb = mHalfExtents[0] * abs_r[2][1] + mHalfExtents[2] * abs_r[0][1];
  57. if (abs(rot(0, 3) * rot(2, 1) - rot(2, 3) * rot(0, 1)) > ra + rb) return false;
  58. // Test axis L = A1 x B2
  59. ra = a_half_extents[0] * abs_r[2][2] + a_half_extents[2] * abs_r[2][0];
  60. rb = mHalfExtents[0] * abs_r[1][1] + mHalfExtents[1] * abs_r[0][1];
  61. if (abs(rot(0, 3) * rot(2, 2) - rot(2, 3) * rot(0, 2)) > ra + rb) return false;
  62. // Test axis L = A2 x B0
  63. ra = a_half_extents[0] * abs_r[0][1] + a_half_extents[1] * abs_r[0][0];
  64. rb = mHalfExtents[1] * abs_r[2][2] + mHalfExtents[2] * abs_r[1][2];
  65. if (abs(rot(1, 3) * rot(0, 0) - rot(0, 3) * rot(1, 0)) > ra + rb) return false;
  66. // Test axis L = A2 x B1
  67. ra = a_half_extents[0] * abs_r[1][1] + a_half_extents[1] * abs_r[1][0];
  68. rb = mHalfExtents[0] * abs_r[2][2] + mHalfExtents[2] * abs_r[0][2];
  69. if (abs(rot(1, 3) * rot(0, 1) - rot(0, 3) * rot(1, 1)) > ra + rb) return false;
  70. // Test axis L = A2 x B2
  71. ra = a_half_extents[0] * abs_r[2][1] + a_half_extents[1] * abs_r[2][0];
  72. rb = mHalfExtents[0] * abs_r[1][2] + mHalfExtents[1] * abs_r[0][2];
  73. if (abs(rot(1, 3) * rot(0, 2) - rot(0, 3) * rot(1, 2)) > ra + rb) return false;
  74. // Since no separating axis is found, the OBB and AAB must be intersecting
  75. return true;
  76. }
  77. bool OrientedBox::Overlaps(const OrientedBox &inBox, float inEpsilon) const
  78. {
  79. // Taken from: Real Time Collision Detection - Christer Ericson
  80. // Chapter 4.4.1, page 103-105.
  81. // Note that A is this, B is inBox
  82. // Compute rotation matrix expressing b in a's coordinate frame
  83. Mat44 rot = mOrientation.InversedRotationTranslation() * inBox.mOrientation;
  84. // Compute common subexpressions. Add in an epsilon term to
  85. // counteract arithmetic errors when two edges are parallel and
  86. // their cross product is (near) null (see text for details)
  87. Vec3 epsilon = Vec3::sReplicate(inEpsilon);
  88. Vec3 abs_r[3] { rot.GetAxisX().Abs() + epsilon, rot.GetAxisY().Abs() + epsilon, rot.GetAxisZ().Abs() + epsilon };
  89. // Test axes L = A0, L = A1, L = A2
  90. float ra, rb;
  91. for (int i = 0; i < 3; i++)
  92. {
  93. ra = mHalfExtents[i];
  94. rb = inBox.mHalfExtents[0] * abs_r[0][i] + inBox.mHalfExtents[1] * abs_r[1][i] + inBox.mHalfExtents[2] * abs_r[2][i];
  95. if (abs(rot(i, 3)) > ra + rb) return false;
  96. }
  97. // Test axes L = B0, L = B1, L = B2
  98. for (int i = 0; i < 3; i++)
  99. {
  100. ra = mHalfExtents.Dot(abs_r[i]);
  101. rb = inBox.mHalfExtents[i];
  102. if (abs(rot.GetTranslation().Dot(rot.GetColumn3(i))) > ra + rb) return false;
  103. }
  104. // Test axis L = A0 x B0
  105. ra = mHalfExtents[1] * abs_r[0][2] + mHalfExtents[2] * abs_r[0][1];
  106. rb = inBox.mHalfExtents[1] * abs_r[2][0] + inBox.mHalfExtents[2] * abs_r[1][0];
  107. if (abs(rot(2, 3) * rot(1, 0) - rot(1, 3) * rot(2, 0)) > ra + rb) return false;
  108. // Test axis L = A0 x B1
  109. ra = mHalfExtents[1] * abs_r[1][2] + mHalfExtents[2] * abs_r[1][1];
  110. rb = inBox.mHalfExtents[0] * abs_r[2][0] + inBox.mHalfExtents[2] * abs_r[0][0];
  111. if (abs(rot(2, 3) * rot(1, 1) - rot(1, 3) * rot(2, 1)) > ra + rb) return false;
  112. // Test axis L = A0 x B2
  113. ra = mHalfExtents[1] * abs_r[2][2] + mHalfExtents[2] * abs_r[2][1];
  114. rb = inBox.mHalfExtents[0] * abs_r[1][0] + inBox.mHalfExtents[1] * abs_r[0][0];
  115. if (abs(rot(2, 3) * rot(1, 2) - rot(1, 3) * rot(2, 2)) > ra + rb) return false;
  116. // Test axis L = A1 x B0
  117. ra = mHalfExtents[0] * abs_r[0][2] + mHalfExtents[2] * abs_r[0][0];
  118. rb = inBox.mHalfExtents[1] * abs_r[2][1] + inBox.mHalfExtents[2] * abs_r[1][1];
  119. if (abs(rot(0, 3) * rot(2, 0) - rot(2, 3) * rot(0, 0)) > ra + rb) return false;
  120. // Test axis L = A1 x B1
  121. ra = mHalfExtents[0] * abs_r[1][2] + mHalfExtents[2] * abs_r[1][0];
  122. rb = inBox.mHalfExtents[0] * abs_r[2][1] + inBox.mHalfExtents[2] * abs_r[0][1];
  123. if (abs(rot(0, 3) * rot(2, 1) - rot(2, 3) * rot(0, 1)) > ra + rb) return false;
  124. // Test axis L = A1 x B2
  125. ra = mHalfExtents[0] * abs_r[2][2] + mHalfExtents[2] * abs_r[2][0];
  126. rb = inBox.mHalfExtents[0] * abs_r[1][1] + inBox.mHalfExtents[1] * abs_r[0][1];
  127. if (abs(rot(0, 3) * rot(2, 2) - rot(2, 3) * rot(0, 2)) > ra + rb) return false;
  128. // Test axis L = A2 x B0
  129. ra = mHalfExtents[0] * abs_r[0][1] + mHalfExtents[1] * abs_r[0][0];
  130. rb = inBox.mHalfExtents[1] * abs_r[2][2] + inBox.mHalfExtents[2] * abs_r[1][2];
  131. if (abs(rot(1, 3) * rot(0, 0) - rot(0, 3) * rot(1, 0)) > ra + rb) return false;
  132. // Test axis L = A2 x B1
  133. ra = mHalfExtents[0] * abs_r[1][1] + mHalfExtents[1] * abs_r[1][0];
  134. rb = inBox.mHalfExtents[0] * abs_r[2][2] + inBox.mHalfExtents[2] * abs_r[0][2];
  135. if (abs(rot(1, 3) * rot(0, 1) - rot(0, 3) * rot(1, 1)) > ra + rb) return false;
  136. // Test axis L = A2 x B2
  137. ra = mHalfExtents[0] * abs_r[2][1] + mHalfExtents[1] * abs_r[2][0];
  138. rb = inBox.mHalfExtents[0] * abs_r[1][2] + inBox.mHalfExtents[1] * abs_r[0][2];
  139. if (abs(rot(1, 3) * rot(0, 2) - rot(0, 3) * rot(1, 2)) > ra + rb) return false;
  140. // Since no separating axis is found, the OBBs must be intersecting
  141. return true;
  142. }
  143. JPH_NAMESPACE_END