BoundingBox.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. // Copyright (c) 2008-2023 the Urho3D project
  2. // License: MIT
  3. #include "../Precompiled.h"
  4. #include "../Math/Frustum.h"
  5. #include "../Math/Polyhedron.h"
  6. #include "../DebugNew.h"
  7. namespace Urho3D
  8. {
  9. void BoundingBox::Define(const Vector3* vertices, unsigned count)
  10. {
  11. Clear();
  12. if (!count)
  13. return;
  14. Merge(vertices, count);
  15. }
  16. void BoundingBox::Define(const Frustum& frustum)
  17. {
  18. Clear();
  19. Define(frustum.vertices_, NUM_FRUSTUM_VERTICES);
  20. }
  21. void BoundingBox::Define(const Polyhedron& poly)
  22. {
  23. Clear();
  24. Merge(poly);
  25. }
  26. void BoundingBox::Define(const Sphere& sphere)
  27. {
  28. const Vector3& center = sphere.center_;
  29. float radius = sphere.radius_;
  30. min_ = center + Vector3(-radius, -radius, -radius);
  31. max_ = center + Vector3(radius, radius, radius);
  32. }
  33. void BoundingBox::Merge(const Vector3* vertices, unsigned count)
  34. {
  35. while (count--)
  36. Merge(*vertices++);
  37. }
  38. void BoundingBox::Merge(const Frustum& frustum)
  39. {
  40. Merge(frustum.vertices_, NUM_FRUSTUM_VERTICES);
  41. }
  42. void BoundingBox::Merge(const Polyhedron& poly)
  43. {
  44. for (const Vector<Vector3>& face : poly.faces_)
  45. {
  46. if (!face.Empty())
  47. Merge(&face[0], face.Size());
  48. }
  49. }
  50. void BoundingBox::Merge(const Sphere& sphere)
  51. {
  52. const Vector3& center = sphere.center_;
  53. float radius = sphere.radius_;
  54. Merge(center + Vector3(radius, radius, radius));
  55. Merge(center + Vector3(-radius, -radius, -radius));
  56. }
  57. void BoundingBox::Clip(const BoundingBox& box)
  58. {
  59. if (box.min_.x_ > min_.x_)
  60. min_.x_ = box.min_.x_;
  61. if (box.max_.x_ < max_.x_)
  62. max_.x_ = box.max_.x_;
  63. if (box.min_.y_ > min_.y_)
  64. min_.y_ = box.min_.y_;
  65. if (box.max_.y_ < max_.y_)
  66. max_.y_ = box.max_.y_;
  67. if (box.min_.z_ > min_.z_)
  68. min_.z_ = box.min_.z_;
  69. if (box.max_.z_ < max_.z_)
  70. max_.z_ = box.max_.z_;
  71. if (min_.x_ > max_.x_ || min_.y_ > max_.y_ || min_.z_ > max_.z_)
  72. {
  73. min_ = Vector3(M_INFINITY, M_INFINITY, M_INFINITY);
  74. max_ = Vector3(-M_INFINITY, -M_INFINITY, -M_INFINITY);
  75. }
  76. }
  77. void BoundingBox::Transform(const Matrix3& transform)
  78. {
  79. *this = Transformed(Matrix3x4(transform));
  80. }
  81. void BoundingBox::Transform(const Matrix3x4& transform)
  82. {
  83. *this = Transformed(transform);
  84. }
  85. BoundingBox BoundingBox::Transformed(const Matrix3& transform) const
  86. {
  87. return Transformed(Matrix3x4(transform));
  88. }
  89. BoundingBox BoundingBox::Transformed(const Matrix3x4& transform) const
  90. {
  91. #ifdef URHO3D_SSE
  92. const __m128 one = _mm_set_ss(1.f);
  93. __m128 minPt = _mm_movelh_ps(_mm_loadl_pi(_mm_setzero_ps(), (const __m64*)&min_.x_), _mm_unpacklo_ps(_mm_set_ss(min_.z_), one));
  94. __m128 maxPt = _mm_movelh_ps(_mm_loadl_pi(_mm_setzero_ps(), (const __m64*)&max_.x_), _mm_unpacklo_ps(_mm_set_ss(max_.z_), one));
  95. __m128 centerPoint = _mm_mul_ps(_mm_add_ps(minPt, maxPt), _mm_set1_ps(0.5f));
  96. __m128 halfSize = _mm_sub_ps(centerPoint, minPt);
  97. __m128 m0 = _mm_loadu_ps(&transform.m00_);
  98. __m128 m1 = _mm_loadu_ps(&transform.m10_);
  99. __m128 m2 = _mm_loadu_ps(&transform.m20_);
  100. __m128 r0 = _mm_mul_ps(m0, centerPoint);
  101. __m128 r1 = _mm_mul_ps(m1, centerPoint);
  102. __m128 t0 = _mm_add_ps(_mm_unpacklo_ps(r0, r1), _mm_unpackhi_ps(r0, r1));
  103. __m128 r2 = _mm_mul_ps(m2, centerPoint);
  104. const __m128 zero = _mm_setzero_ps();
  105. __m128 t2 = _mm_add_ps(_mm_unpacklo_ps(r2, zero), _mm_unpackhi_ps(r2, zero));
  106. __m128 newCenter = _mm_add_ps(_mm_movelh_ps(t0, t2), _mm_movehl_ps(t2, t0));
  107. const __m128 absMask = _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF));
  108. __m128 x = _mm_and_ps(absMask, _mm_mul_ps(m0, halfSize));
  109. __m128 y = _mm_and_ps(absMask, _mm_mul_ps(m1, halfSize));
  110. __m128 z = _mm_and_ps(absMask, _mm_mul_ps(m2, halfSize));
  111. t0 = _mm_add_ps(_mm_unpacklo_ps(x, y), _mm_unpackhi_ps(x, y));
  112. t2 = _mm_add_ps(_mm_unpacklo_ps(z, zero), _mm_unpackhi_ps(z, zero));
  113. __m128 newDir = _mm_add_ps(_mm_movelh_ps(t0, t2), _mm_movehl_ps(t2, t0));
  114. return BoundingBox(_mm_sub_ps(newCenter, newDir), _mm_add_ps(newCenter, newDir));
  115. #else
  116. Vector3 newCenter = transform * Center();
  117. Vector3 oldEdge = Size() * 0.5f;
  118. Vector3 newEdge = Vector3(
  119. Abs(transform.m00_) * oldEdge.x_ + Abs(transform.m01_) * oldEdge.y_ + Abs(transform.m02_) * oldEdge.z_,
  120. Abs(transform.m10_) * oldEdge.x_ + Abs(transform.m11_) * oldEdge.y_ + Abs(transform.m12_) * oldEdge.z_,
  121. Abs(transform.m20_) * oldEdge.x_ + Abs(transform.m21_) * oldEdge.y_ + Abs(transform.m22_) * oldEdge.z_
  122. );
  123. return BoundingBox(newCenter - newEdge, newCenter + newEdge);
  124. #endif
  125. }
  126. Rect BoundingBox::Projected(const Matrix4& projection) const
  127. {
  128. Vector3 projMin = min_;
  129. Vector3 projMax = max_;
  130. if (projMin.z_ < M_MIN_NEARCLIP)
  131. projMin.z_ = M_MIN_NEARCLIP;
  132. if (projMax.z_ < M_MIN_NEARCLIP)
  133. projMax.z_ = M_MIN_NEARCLIP;
  134. Vector3 vertices[8];
  135. vertices[0] = projMin;
  136. vertices[1] = Vector3(projMax.x_, projMin.y_, projMin.z_);
  137. vertices[2] = Vector3(projMin.x_, projMax.y_, projMin.z_);
  138. vertices[3] = Vector3(projMax.x_, projMax.y_, projMin.z_);
  139. vertices[4] = Vector3(projMin.x_, projMin.y_, projMax.z_);
  140. vertices[5] = Vector3(projMax.x_, projMin.y_, projMax.z_);
  141. vertices[6] = Vector3(projMin.x_, projMax.y_, projMax.z_);
  142. vertices[7] = projMax;
  143. Rect rect;
  144. for (const auto& vertice : vertices)
  145. {
  146. Vector3 projected = projection * vertice;
  147. rect.Merge(Vector2(projected.x_, projected.y_));
  148. }
  149. return rect;
  150. }
  151. float BoundingBox::DistanceToPoint(const Vector3& point) const
  152. {
  153. const Vector3 offset = Center() - point;
  154. const Vector3 absOffset(Abs(offset.x_), Abs(offset.y_), Abs(offset.z_));
  155. return VectorMax(Vector3::ZERO, absOffset - HalfSize()).Length();
  156. }
  157. Intersection BoundingBox::IsInside(const Sphere& sphere) const
  158. {
  159. float distSquared = 0;
  160. float temp;
  161. const Vector3& center = sphere.center_;
  162. if (center.x_ < min_.x_)
  163. {
  164. temp = center.x_ - min_.x_;
  165. distSquared += temp * temp;
  166. }
  167. else if (center.x_ > max_.x_)
  168. {
  169. temp = center.x_ - max_.x_;
  170. distSquared += temp * temp;
  171. }
  172. if (center.y_ < min_.y_)
  173. {
  174. temp = center.y_ - min_.y_;
  175. distSquared += temp * temp;
  176. }
  177. else if (center.y_ > max_.y_)
  178. {
  179. temp = center.y_ - max_.y_;
  180. distSquared += temp * temp;
  181. }
  182. if (center.z_ < min_.z_)
  183. {
  184. temp = center.z_ - min_.z_;
  185. distSquared += temp * temp;
  186. }
  187. else if (center.z_ > max_.z_)
  188. {
  189. temp = center.z_ - max_.z_;
  190. distSquared += temp * temp;
  191. }
  192. float radius = sphere.radius_;
  193. if (distSquared >= radius * radius)
  194. return OUTSIDE;
  195. else if (center.x_ - radius < min_.x_ || center.x_ + radius > max_.x_ || center.y_ - radius < min_.y_ ||
  196. center.y_ + radius > max_.y_ || center.z_ - radius < min_.z_ || center.z_ + radius > max_.z_)
  197. return INTERSECTS;
  198. else
  199. return INSIDE;
  200. }
  201. Intersection BoundingBox::IsInsideFast(const Sphere& sphere) const
  202. {
  203. float distSquared = 0;
  204. float temp;
  205. const Vector3& center = sphere.center_;
  206. if (center.x_ < min_.x_)
  207. {
  208. temp = center.x_ - min_.x_;
  209. distSquared += temp * temp;
  210. }
  211. else if (center.x_ > max_.x_)
  212. {
  213. temp = center.x_ - max_.x_;
  214. distSquared += temp * temp;
  215. }
  216. if (center.y_ < min_.y_)
  217. {
  218. temp = center.y_ - min_.y_;
  219. distSquared += temp * temp;
  220. }
  221. else if (center.y_ > max_.y_)
  222. {
  223. temp = center.y_ - max_.y_;
  224. distSquared += temp * temp;
  225. }
  226. if (center.z_ < min_.z_)
  227. {
  228. temp = center.z_ - min_.z_;
  229. distSquared += temp * temp;
  230. }
  231. else if (center.z_ > max_.z_)
  232. {
  233. temp = center.z_ - max_.z_;
  234. distSquared += temp * temp;
  235. }
  236. float radius = sphere.radius_;
  237. if (distSquared >= radius * radius)
  238. return OUTSIDE;
  239. else
  240. return INSIDE;
  241. }
  242. String BoundingBox::ToString() const
  243. {
  244. return min_.ToString() + " - " + max_.ToString();
  245. }
  246. }