BoundingBox.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 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. void BoundingBox::Define(const Vector3* vertices, unsigned count)
  26. {
  27. if (!count)
  28. return;
  29. defined_ = false;
  30. Merge(vertices, count);
  31. }
  32. void BoundingBox::Define(const Frustum& frustum)
  33. {
  34. Define(frustum.GetVertices(), NUM_FRUSTUM_VERTICES);
  35. }
  36. void BoundingBox::Define(const Sphere& sphere)
  37. {
  38. const Vector3& center = sphere.center_;
  39. float radius = sphere.radius_;
  40. min_ = center + Vector3(-radius, -radius, -radius);
  41. max_ = center + Vector3(radius, radius, radius);
  42. defined_ = true;
  43. }
  44. void BoundingBox::Merge(const Vector3* vertices, unsigned count)
  45. {
  46. while (count--)
  47. {
  48. Merge(*vertices);
  49. ++vertices;
  50. }
  51. }
  52. void BoundingBox::Merge(const Frustum& frustum)
  53. {
  54. Merge(frustum.GetVertices(), NUM_FRUSTUM_VERTICES);
  55. }
  56. void BoundingBox::Merge(const Sphere& sphere)
  57. {
  58. const Vector3& center = sphere.center_;
  59. float radius = sphere.radius_;
  60. Merge(center + Vector3(radius, radius, radius));
  61. Merge(center + Vector3(-radius, -radius, -radius));
  62. }
  63. void BoundingBox::Intersect(const BoundingBox& box)
  64. {
  65. if (box.min_.x_ > min_.x_)
  66. min_.x_ = box.min_.x_;
  67. if (box.max_.x_ < max_.x_)
  68. max_.x_ = box.max_.x_;
  69. if (box.min_.y_ > min_.y_)
  70. min_.y_ = box.min_.y_;
  71. if (box.max_.y_ < max_.y_)
  72. max_.y_ = box.max_.y_;
  73. if (box.min_.z_ > min_.z_)
  74. min_.z_ = box.min_.z_;
  75. if (box.max_.z_ < max_.z_)
  76. max_.z_ = box.max_.z_;
  77. float temp;
  78. if (min_.x_ > max_.x_)
  79. {
  80. temp = min_.x_;
  81. min_.x_ = max_.x_;
  82. max_.x_ = temp;
  83. }
  84. if (min_.y_ > max_.y_)
  85. {
  86. temp = min_.y_;
  87. min_.y_ = max_.y_;
  88. max_.y_ = temp;
  89. }
  90. if (min_.z_ > max_.z_)
  91. {
  92. temp = min_.z_;
  93. min_.z_ = max_.z_;
  94. max_.z_ = temp;
  95. }
  96. }
  97. void BoundingBox::Transform(const Matrix3& transform)
  98. {
  99. Vector3 newCenter = transform * GetCenter();
  100. Vector3 oldEdge = GetSize() * 0.5;
  101. Vector3 newEdge = Vector3(
  102. fabsf(transform.m00_) * oldEdge.x_ + fabsf(transform.m01_) * oldEdge.y_ + fabsf(transform.m02_) * oldEdge.z_,
  103. fabsf(transform.m10_) * oldEdge.x_ + fabsf(transform.m11_) * oldEdge.y_ + fabsf(transform.m12_) * oldEdge.z_,
  104. fabsf(transform.m20_) * oldEdge.x_ + fabsf(transform.m21_) * oldEdge.y_ + fabsf(transform.m22_) * oldEdge.z_
  105. );
  106. min_ = newCenter - newEdge;
  107. max_ = newCenter + newEdge;
  108. }
  109. void BoundingBox::Transform(const Matrix4x3& transform)
  110. {
  111. Vector3 newCenter = transform * GetCenter();
  112. Vector3 oldEdge = GetSize() * 0.5;
  113. Vector3 newEdge = Vector3(
  114. fabsf(transform.m00_) * oldEdge.x_ + fabsf(transform.m01_) * oldEdge.y_ + fabsf(transform.m02_) * oldEdge.z_,
  115. fabsf(transform.m10_) * oldEdge.x_ + fabsf(transform.m11_) * oldEdge.y_ + fabsf(transform.m12_) * oldEdge.z_,
  116. fabsf(transform.m20_) * oldEdge.x_ + fabsf(transform.m21_) * oldEdge.y_ + fabsf(transform.m22_) * oldEdge.z_
  117. );
  118. min_ = newCenter - newEdge;
  119. max_ = newCenter + newEdge;
  120. }
  121. BoundingBox BoundingBox::GetTransformed(const Matrix3& transform) const
  122. {
  123. Vector3 newCenter = transform * GetCenter();
  124. Vector3 oldEdge = GetSize() * 0.5;
  125. Vector3 newEdge = Vector3(
  126. fabsf(transform.m00_) * oldEdge.x_ + fabsf(transform.m01_) * oldEdge.y_ + fabsf(transform.m02_) * oldEdge.z_,
  127. fabsf(transform.m10_) * oldEdge.x_ + fabsf(transform.m11_) * oldEdge.y_ + fabsf(transform.m12_) * oldEdge.z_,
  128. fabsf(transform.m20_) * oldEdge.x_ + fabsf(transform.m21_) * oldEdge.y_ + fabsf(transform.m22_) * oldEdge.z_
  129. );
  130. return BoundingBox(newCenter - newEdge, newCenter + newEdge);
  131. }
  132. BoundingBox BoundingBox::GetTransformed(const Matrix4x3& transform) const
  133. {
  134. Vector3 newCenter = transform * GetCenter();
  135. Vector3 oldEdge = GetSize() * 0.5f;
  136. Vector3 newEdge = Vector3(
  137. fabsf(transform.m00_) * oldEdge.x_ + fabsf(transform.m01_) * oldEdge.y_ + fabsf(transform.m02_) * oldEdge.z_,
  138. fabsf(transform.m10_) * oldEdge.x_ + fabsf(transform.m11_) * oldEdge.y_ + fabsf(transform.m12_) * oldEdge.z_,
  139. fabsf(transform.m20_) * oldEdge.x_ + fabsf(transform.m21_) * oldEdge.y_ + fabsf(transform.m22_) * oldEdge.z_
  140. );
  141. return BoundingBox(newCenter - newEdge, newCenter + newEdge);
  142. }
  143. Rect BoundingBox::GetProjected(const Matrix4& projection) const
  144. {
  145. Vector3 projMin = min_;
  146. Vector3 projMax = max_;
  147. if (projMin.z_ < M_MIN_NEARCLIP)
  148. projMin.z_ = M_MIN_NEARCLIP;
  149. if (projMax.z_ < M_MIN_NEARCLIP)
  150. projMax.z_ = M_MIN_NEARCLIP;
  151. Vector3 vertices[8];
  152. vertices[0] = projMin;
  153. vertices[1] = Vector3(projMax.x_, projMin.y_, projMin.z_);
  154. vertices[2] = Vector3(projMin.x_, projMax.y_, projMin.z_);
  155. vertices[3] = Vector3(projMax.x_, projMax.y_, projMin.z_);
  156. vertices[4] = Vector3(projMin.x_, projMin.y_, projMax.z_);
  157. vertices[5] = Vector3(projMax.x_, projMin.y_, projMax.z_);
  158. vertices[6] = Vector3(projMin.x_, projMax.y_, projMax.z_);
  159. vertices[7] = projMax;
  160. Rect rect;
  161. for (unsigned i = 0; i < 8; ++i)
  162. {
  163. Vector3 projected = projection * vertices[i];
  164. rect.Merge(Vector2(projected.x_, projected.y_));
  165. }
  166. return rect;
  167. }
  168. Intersection BoundingBox::IsInside(const Sphere& sphere) const
  169. {
  170. float distSquared = 0;
  171. float temp;
  172. const Vector3& center = sphere.center_;
  173. if (center.x_ < min_.x_)
  174. {
  175. temp = center.x_ - min_.x_;
  176. distSquared += temp * temp;
  177. }
  178. else if (center.x_ > max_.x_)
  179. {
  180. temp = center.x_ - max_.x_;
  181. distSquared += temp * temp;
  182. }
  183. if (center.y_ < min_.y_)
  184. {
  185. temp = center.y_ - min_.y_;
  186. distSquared += temp * temp;
  187. }
  188. else if (center.y_ > max_.y_)
  189. {
  190. temp = center.y_ - max_.y_;
  191. distSquared += temp * temp;
  192. }
  193. if (center.z_ < min_.z_)
  194. {
  195. temp = center.z_ - min_.z_;
  196. distSquared += temp * temp;
  197. }
  198. else if (center.z_ > max_.z_)
  199. {
  200. temp = center.z_ - max_.z_;
  201. distSquared += temp * temp;
  202. }
  203. float radius = sphere.radius_;
  204. if (distSquared >= radius * radius)
  205. return OUTSIDE;
  206. if ((center.x_ - radius < min_.x_) || (center.x_ + radius > max_.x_))
  207. return INTERSECTS;
  208. if ((center.y_ - radius < min_.y_) || (center.y_ + radius > max_.y_))
  209. return INTERSECTS;
  210. if ((center.z_ - radius < min_.z_) || (center.z_ + radius > max_.z_))
  211. return INTERSECTS;
  212. return INSIDE;
  213. }
  214. Intersection BoundingBox::IsInsideFast(const Sphere& sphere) const
  215. {
  216. float distSquared = 0;
  217. float temp;
  218. const Vector3& center = sphere.center_;
  219. if (center.x_ < min_.x_)
  220. {
  221. temp = center.x_ - min_.x_;
  222. distSquared += temp * temp;
  223. }
  224. else if (center.x_ > max_.x_)
  225. {
  226. temp = center.x_ - max_.x_;
  227. distSquared += temp * temp;
  228. }
  229. if (center.y_ < min_.y_)
  230. {
  231. temp = center.y_ - min_.y_;
  232. distSquared += temp * temp;
  233. }
  234. else if (center.y_ > max_.y_)
  235. {
  236. temp = center.y_ - max_.y_;
  237. distSquared += temp * temp;
  238. }
  239. if (center.z_ < min_.z_)
  240. {
  241. temp = center.z_ - min_.z_;
  242. distSquared += temp * temp;
  243. }
  244. else if (center.z_ > max_.z_)
  245. {
  246. temp = center.z_ - max_.z_;
  247. distSquared += temp * temp;
  248. }
  249. float radius = sphere.radius_;
  250. if (distSquared >= radius * radius)
  251. return OUTSIDE;
  252. return INSIDE;
  253. }
  254. float BoundingBox::GetDistance(const Ray& ray) const
  255. {
  256. // If undefined, no hit (infinite distance)
  257. if (!defined_)
  258. return M_INFINITY;
  259. // Check for ray origin being inside the box
  260. if (IsInside(ray.origin_))
  261. return 0.0f;
  262. float dist = M_INFINITY;
  263. // Check for intersecting in the X-direction
  264. if ((ray.origin_.x_ < min_.x_) && (ray.direction_.x_ > 0.0f))
  265. {
  266. float x = (min_.x_ - ray.origin_.x_) / ray.direction_.x_;
  267. if (x < dist)
  268. {
  269. Vector3 point = ray.origin_ + x * ray.direction_;
  270. if ((point.y_ >= min_.y_) && (point.y_ <= max_.y_) &&
  271. (point.z_ >= min_.z_) && (point.z_ <= max_.z_))
  272. dist = x;
  273. }
  274. }
  275. if ((ray.origin_.x_ > max_.x_) && (ray.direction_.x_ < 0.0f))
  276. {
  277. float x = (max_.x_ - ray.origin_.x_) / ray.direction_.x_;
  278. if (x < dist)
  279. {
  280. Vector3 point = ray.origin_ + x * ray.direction_;
  281. if ((point.y_ >= min_.y_) && (point.y_ <= max_.y_) &&
  282. (point.z_ >= min_.z_) && (point.z_ <= max_.z_))
  283. dist = x;
  284. }
  285. }
  286. // Check for intersecting in the Y-direction
  287. if ((ray.origin_.y_ < min_.y_) && (ray.direction_.y_ > 0.0f))
  288. {
  289. float x = (min_.y_ - ray.origin_.y_) / ray.direction_.y_;
  290. if (x < dist)
  291. {
  292. Vector3 point = ray.origin_ + x * ray.direction_;
  293. if ((point.x_ >= min_.x_) && (point.x_ <= max_.x_) &&
  294. (point.z_ >= min_.z_) && (point.z_ <= max_.z_))
  295. dist = x;
  296. }
  297. }
  298. if ((ray.origin_.y_ > max_.y_) && (ray.direction_.y_ < 0.0f))
  299. {
  300. float x = (max_.y_ - ray.origin_.y_) / ray.direction_.y_;
  301. if (x < dist)
  302. {
  303. Vector3 point = ray.origin_ + x * ray.direction_;
  304. if ((point.x_ >= min_.x_) && (point.x_ <= max_.x_) &&
  305. (point.z_ >= min_.z_) && (point.z_ <= max_.z_))
  306. dist = x;
  307. }
  308. }
  309. // Check for intersecting in the Z-direction
  310. if ((ray.origin_.z_ < min_.z_) && (ray.direction_.z_ > 0.0f))
  311. {
  312. float x = (min_.z_ - ray.origin_.z_) / ray.direction_.z_;
  313. if (x < dist)
  314. {
  315. Vector3 point = ray.origin_ + x * ray.direction_;
  316. if ((point.x_ >= min_.x_) && (point.x_ <= max_.x_) &&
  317. (point.y_ >= min_.y_) && (point.y_ <= max_.y_))
  318. dist = x;
  319. }
  320. }
  321. if ((ray.origin_.z_ > max_.z_) && (ray.direction_.z_ < 0.0f))
  322. {
  323. float x = (max_.z_ - ray.origin_.z_) / ray.direction_.z_;
  324. if (x < dist)
  325. {
  326. Vector3 point = ray.origin_ + x * ray.direction_;
  327. if ((point.x_ >= min_.x_) && (point.x_ <= max_.x_) &&
  328. (point.y_ >= min_.y_) && (point.y_ <= max_.y_))
  329. dist = x;
  330. }
  331. }
  332. return dist;
  333. }