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