BoundingBox.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2012 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "Frustum.h"
  25. #include "Polyhedron.h"
  26. void BoundingBox::Define(const Vector3* vertices, unsigned count)
  27. {
  28. if (!count)
  29. return;
  30. defined_ = false;
  31. Merge(vertices, count);
  32. }
  33. void BoundingBox::Define(const Frustum& frustum)
  34. {
  35. Define(frustum.vertices_, NUM_FRUSTUM_VERTICES);
  36. }
  37. void BoundingBox::Define(const Polyhedron& poly)
  38. {
  39. defined_ = false;
  40. Merge(poly);
  41. }
  42. void BoundingBox::Define(const Sphere& sphere)
  43. {
  44. const Vector3& center = sphere.center_;
  45. float radius = sphere.radius_;
  46. min_ = center + Vector3(-radius, -radius, -radius);
  47. max_ = center + Vector3(radius, radius, radius);
  48. defined_ = true;
  49. }
  50. void BoundingBox::Merge(const Vector3* vertices, unsigned count)
  51. {
  52. while (count--)
  53. {
  54. Merge(*vertices);
  55. ++vertices;
  56. }
  57. }
  58. void BoundingBox::Merge(const Frustum& frustum)
  59. {
  60. Merge(frustum.vertices_, NUM_FRUSTUM_VERTICES);
  61. }
  62. void BoundingBox::Merge(const Polyhedron& poly)
  63. {
  64. for (unsigned i = 0; i < poly.faces_.Size(); ++i)
  65. {
  66. const PODVector<Vector3>& face = poly.faces_[i];
  67. if (!face.Empty())
  68. Merge(&face[0], face.Size());
  69. }
  70. }
  71. void BoundingBox::Merge(const Sphere& sphere)
  72. {
  73. const Vector3& center = sphere.center_;
  74. float radius = sphere.radius_;
  75. Merge(center + Vector3(radius, radius, radius));
  76. Merge(center + Vector3(-radius, -radius, -radius));
  77. }
  78. void BoundingBox::Clip(const BoundingBox& box)
  79. {
  80. if (box.min_.x_ > min_.x_)
  81. min_.x_ = box.min_.x_;
  82. if (box.max_.x_ < max_.x_)
  83. max_.x_ = box.max_.x_;
  84. if (box.min_.y_ > min_.y_)
  85. min_.y_ = box.min_.y_;
  86. if (box.max_.y_ < max_.y_)
  87. max_.y_ = box.max_.y_;
  88. if (box.min_.z_ > min_.z_)
  89. min_.z_ = box.min_.z_;
  90. if (box.max_.z_ < max_.z_)
  91. max_.z_ = box.max_.z_;
  92. float temp;
  93. if (min_.x_ > max_.x_)
  94. {
  95. temp = min_.x_;
  96. min_.x_ = max_.x_;
  97. max_.x_ = temp;
  98. }
  99. if (min_.y_ > max_.y_)
  100. {
  101. temp = min_.y_;
  102. min_.y_ = max_.y_;
  103. max_.y_ = temp;
  104. }
  105. if (min_.z_ > max_.z_)
  106. {
  107. temp = min_.z_;
  108. min_.z_ = max_.z_;
  109. max_.z_ = temp;
  110. }
  111. }
  112. void BoundingBox::Transform(const Matrix3& transform)
  113. {
  114. Vector3 newCenter = transform * Center();
  115. Vector3 oldEdge = Size() * 0.5f;
  116. Vector3 newEdge = Vector3(
  117. fabsf(transform.m00_) * oldEdge.x_ + fabsf(transform.m01_) * oldEdge.y_ + fabsf(transform.m02_) * oldEdge.z_,
  118. fabsf(transform.m10_) * oldEdge.x_ + fabsf(transform.m11_) * oldEdge.y_ + fabsf(transform.m12_) * oldEdge.z_,
  119. fabsf(transform.m20_) * oldEdge.x_ + fabsf(transform.m21_) * oldEdge.y_ + fabsf(transform.m22_) * oldEdge.z_
  120. );
  121. min_ = newCenter - newEdge;
  122. max_ = newCenter + newEdge;
  123. }
  124. void BoundingBox::Transform(const Matrix3x4& transform)
  125. {
  126. Vector3 newCenter = transform * Center();
  127. Vector3 oldEdge = Size() * 0.5f;
  128. Vector3 newEdge = Vector3(
  129. fabsf(transform.m00_) * oldEdge.x_ + fabsf(transform.m01_) * oldEdge.y_ + fabsf(transform.m02_) * oldEdge.z_,
  130. fabsf(transform.m10_) * oldEdge.x_ + fabsf(transform.m11_) * oldEdge.y_ + fabsf(transform.m12_) * oldEdge.z_,
  131. fabsf(transform.m20_) * oldEdge.x_ + fabsf(transform.m21_) * oldEdge.y_ + fabsf(transform.m22_) * oldEdge.z_
  132. );
  133. min_ = newCenter - newEdge;
  134. max_ = newCenter + newEdge;
  135. }
  136. BoundingBox BoundingBox::Transformed(const Matrix3& transform) const
  137. {
  138. Vector3 newCenter = transform * Center();
  139. Vector3 oldEdge = Size() * 0.5f;
  140. Vector3 newEdge = Vector3(
  141. fabsf(transform.m00_) * oldEdge.x_ + fabsf(transform.m01_) * oldEdge.y_ + fabsf(transform.m02_) * oldEdge.z_,
  142. fabsf(transform.m10_) * oldEdge.x_ + fabsf(transform.m11_) * oldEdge.y_ + fabsf(transform.m12_) * oldEdge.z_,
  143. fabsf(transform.m20_) * oldEdge.x_ + fabsf(transform.m21_) * oldEdge.y_ + fabsf(transform.m22_) * oldEdge.z_
  144. );
  145. return BoundingBox(newCenter - newEdge, newCenter + newEdge);
  146. }
  147. BoundingBox BoundingBox::Transformed(const Matrix3x4& transform) const
  148. {
  149. Vector3 newCenter = transform * Center();
  150. Vector3 oldEdge = Size() * 0.5f;
  151. Vector3 newEdge = Vector3(
  152. fabsf(transform.m00_) * oldEdge.x_ + fabsf(transform.m01_) * oldEdge.y_ + fabsf(transform.m02_) * oldEdge.z_,
  153. fabsf(transform.m10_) * oldEdge.x_ + fabsf(transform.m11_) * oldEdge.y_ + fabsf(transform.m12_) * oldEdge.z_,
  154. fabsf(transform.m20_) * oldEdge.x_ + fabsf(transform.m21_) * oldEdge.y_ + fabsf(transform.m22_) * oldEdge.z_
  155. );
  156. return BoundingBox(newCenter - newEdge, newCenter + newEdge);
  157. }
  158. Rect BoundingBox::Projected(const Matrix4& projection) const
  159. {
  160. Vector3 projMin = min_;
  161. Vector3 projMax = max_;
  162. if (projMin.z_ < M_MIN_NEARCLIP)
  163. projMin.z_ = M_MIN_NEARCLIP;
  164. if (projMax.z_ < M_MIN_NEARCLIP)
  165. projMax.z_ = M_MIN_NEARCLIP;
  166. Vector3 vertices[8];
  167. vertices[0] = projMin;
  168. vertices[1] = Vector3(projMax.x_, projMin.y_, projMin.z_);
  169. vertices[2] = Vector3(projMin.x_, projMax.y_, projMin.z_);
  170. vertices[3] = Vector3(projMax.x_, projMax.y_, projMin.z_);
  171. vertices[4] = Vector3(projMin.x_, projMin.y_, projMax.z_);
  172. vertices[5] = Vector3(projMax.x_, projMin.y_, projMax.z_);
  173. vertices[6] = Vector3(projMin.x_, projMax.y_, projMax.z_);
  174. vertices[7] = projMax;
  175. Rect rect;
  176. for (unsigned i = 0; i < 8; ++i)
  177. {
  178. Vector3 projected = projection * vertices[i];
  179. rect.Merge(Vector2(projected.x_, projected.y_));
  180. }
  181. return rect;
  182. }
  183. Intersection BoundingBox::IsInside(const Sphere& sphere) const
  184. {
  185. float distSquared = 0;
  186. float temp;
  187. const Vector3& center = sphere.center_;
  188. if (center.x_ < min_.x_)
  189. {
  190. temp = center.x_ - min_.x_;
  191. distSquared += temp * temp;
  192. }
  193. else if (center.x_ > max_.x_)
  194. {
  195. temp = center.x_ - max_.x_;
  196. distSquared += temp * temp;
  197. }
  198. if (center.y_ < min_.y_)
  199. {
  200. temp = center.y_ - min_.y_;
  201. distSquared += temp * temp;
  202. }
  203. else if (center.y_ > max_.y_)
  204. {
  205. temp = center.y_ - max_.y_;
  206. distSquared += temp * temp;
  207. }
  208. if (center.z_ < min_.z_)
  209. {
  210. temp = center.z_ - min_.z_;
  211. distSquared += temp * temp;
  212. }
  213. else if (center.z_ > max_.z_)
  214. {
  215. temp = center.z_ - max_.z_;
  216. distSquared += temp * temp;
  217. }
  218. float radius = sphere.radius_;
  219. if (distSquared >= radius * radius)
  220. return OUTSIDE;
  221. else if (center.x_ - radius < min_.x_ || center.x_ + radius > max_.x_ || center.y_ - radius < min_.y_ ||
  222. center.y_ + radius > max_.y_ || center.z_ - radius < min_.z_ || center.z_ + radius > max_.z_)
  223. return INTERSECTS;
  224. else
  225. return INSIDE;
  226. }
  227. Intersection BoundingBox::IsInsideFast(const Sphere& sphere) const
  228. {
  229. float distSquared = 0;
  230. float temp;
  231. const Vector3& center = sphere.center_;
  232. if (center.x_ < min_.x_)
  233. {
  234. temp = center.x_ - min_.x_;
  235. distSquared += temp * temp;
  236. }
  237. else if (center.x_ > max_.x_)
  238. {
  239. temp = center.x_ - max_.x_;
  240. distSquared += temp * temp;
  241. }
  242. if (center.y_ < min_.y_)
  243. {
  244. temp = center.y_ - min_.y_;
  245. distSquared += temp * temp;
  246. }
  247. else if (center.y_ > max_.y_)
  248. {
  249. temp = center.y_ - max_.y_;
  250. distSquared += temp * temp;
  251. }
  252. if (center.z_ < min_.z_)
  253. {
  254. temp = center.z_ - min_.z_;
  255. distSquared += temp * temp;
  256. }
  257. else if (center.z_ > max_.z_)
  258. {
  259. temp = center.z_ - max_.z_;
  260. distSquared += temp * temp;
  261. }
  262. float radius = sphere.radius_;
  263. if (distSquared >= radius * radius)
  264. return OUTSIDE;
  265. else
  266. return INSIDE;
  267. }