BsAABox.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. //__________________________ Banshee Project - A modern game development toolkit _________________________________//
  2. //_____________________________________ www.banshee-project.com __________________________________________________//
  3. //________________________ Copyright (c) 2014 Marko Pintera. All rights reserved. ________________________________//
  4. #include "BsAABox.h"
  5. #include "BsRay.h"
  6. #include "BsPlane.h"
  7. #include "BsSphere.h"
  8. namespace BansheeEngine
  9. {
  10. const AABox AABox::BOX_EMPTY;
  11. AABox::AABox()
  12. :mMinimum(Vector3::ZERO), mMaximum(Vector3::ONE)
  13. {
  14. // Default to a null box
  15. setMin(Vector3(-0.5f, -0.5f, -0.5f));
  16. setMax(Vector3(0.5f, 0.5f, 0.5f));
  17. }
  18. AABox::AABox(const AABox& copy)
  19. :mMinimum(Vector3::ZERO), mMaximum(Vector3::ONE)
  20. {
  21. setExtents(copy.mMinimum, copy.mMaximum);
  22. }
  23. AABox::AABox(const Vector3& min, const Vector3& max)
  24. :mMinimum(Vector3::ZERO), mMaximum(Vector3::ONE)
  25. {
  26. setExtents(min, max);
  27. }
  28. AABox& AABox::operator=(const AABox& rhs)
  29. {
  30. setExtents(rhs.mMinimum, rhs.mMaximum);
  31. return *this;
  32. }
  33. void AABox::setExtents(const Vector3& min, const Vector3& max)
  34. {
  35. assert( (min.x <= max.x && min.y <= max.y && min.z <= max.z) &&
  36. "The minimum corner of the box must be less than or equal to maximum corner" );
  37. mMinimum = min;
  38. mMaximum = max;
  39. }
  40. void AABox::scale(const Vector3& s)
  41. {
  42. Vector3 center = getCenter();
  43. Vector3 min = center + (mMinimum - center) * s;
  44. Vector3 max = center + (mMaximum - center) * s;
  45. setExtents(min, max);
  46. }
  47. Vector3 AABox::getCorner(CornerEnum cornerToGet) const
  48. {
  49. switch(cornerToGet)
  50. {
  51. case FAR_LEFT_BOTTOM:
  52. return mMinimum;
  53. case FAR_LEFT_TOP:
  54. return Vector3(mMinimum.x, mMaximum.y, mMinimum.z);
  55. case FAR_RIGHT_TOP:
  56. return Vector3(mMaximum.x, mMaximum.y, mMinimum.z);
  57. case FAR_RIGHT_BOTTOM:
  58. return Vector3(mMaximum.x, mMinimum.y, mMinimum.z);
  59. case NEAR_RIGHT_BOTTOM:
  60. return Vector3(mMaximum.x, mMinimum.y, mMaximum.z);
  61. case NEAR_LEFT_BOTTOM:
  62. return Vector3(mMinimum.x, mMinimum.y, mMaximum.z);
  63. case NEAR_LEFT_TOP:
  64. return Vector3(mMinimum.x, mMaximum.y, mMaximum.z);
  65. case NEAR_RIGHT_TOP:
  66. return mMaximum;
  67. default:
  68. return Vector3();
  69. }
  70. }
  71. void AABox::merge(const AABox& rhs)
  72. {
  73. Vector3 min = mMinimum;
  74. Vector3 max = mMaximum;
  75. max.ceil(rhs.mMaximum);
  76. min.floor(rhs.mMinimum);
  77. setExtents(min, max);
  78. }
  79. void AABox::merge(const Vector3& point)
  80. {
  81. mMaximum.ceil(point);
  82. mMinimum.floor(point);
  83. }
  84. void AABox::transform(const Matrix4& matrix)
  85. {
  86. Vector3 oldMin, oldMax, currentCorner;
  87. // Getting the old values so that we can use the existing merge method.
  88. oldMin = mMinimum;
  89. oldMax = mMaximum;
  90. // We sequentially compute the corners in the following order :
  91. // 0, 6, 5, 1, 2, 4, 7, 3
  92. // This sequence allows us to only change one member at a time to get at all corners.
  93. // For each one, we transform it using the matrix
  94. // Which gives the resulting point and merge the resulting point.
  95. // First corner
  96. // min min min
  97. currentCorner = oldMin;
  98. merge(matrix.multiply3x4(currentCorner));
  99. // min,min,max
  100. currentCorner.z = oldMax.z;
  101. merge(matrix.multiply3x4(currentCorner));
  102. // min max max
  103. currentCorner.y = oldMax.y;
  104. merge(matrix.multiply3x4(currentCorner));
  105. // min max min
  106. currentCorner.z = oldMin.z;
  107. merge(matrix.multiply3x4(currentCorner));
  108. // max max min
  109. currentCorner.x = oldMax.x;
  110. merge(matrix.multiply3x4(currentCorner));
  111. // max max max
  112. currentCorner.z = oldMax.z;
  113. merge(matrix.multiply3x4(currentCorner));
  114. // max min max
  115. currentCorner.y = oldMin.y;
  116. merge(matrix.multiply3x4(currentCorner));
  117. // max min min
  118. currentCorner.z = oldMin.z;
  119. merge(matrix.multiply3x4(currentCorner));
  120. }
  121. void AABox::transformAffine(const Matrix4& m)
  122. {
  123. assert(m.isAffine());
  124. Vector3 centre = getCenter();
  125. Vector3 halfSize = getHalfSize();
  126. Vector3 newCentre = m.multiply3x4(centre);
  127. Vector3 newHalfSize(
  128. Math::abs(m[0][0]) * halfSize.x + Math::abs(m[0][1]) * halfSize.y + Math::abs(m[0][2]) * halfSize.z,
  129. Math::abs(m[1][0]) * halfSize.x + Math::abs(m[1][1]) * halfSize.y + Math::abs(m[1][2]) * halfSize.z,
  130. Math::abs(m[2][0]) * halfSize.x + Math::abs(m[2][1]) * halfSize.y + Math::abs(m[2][2]) * halfSize.z);
  131. setExtents(newCentre - newHalfSize, newCentre + newHalfSize);
  132. }
  133. bool AABox::intersects(const AABox& b2) const
  134. {
  135. // Use up to 6 separating planes
  136. if (mMaximum.x < b2.mMinimum.x)
  137. return false;
  138. if (mMaximum.y < b2.mMinimum.y)
  139. return false;
  140. if (mMaximum.z < b2.mMinimum.z)
  141. return false;
  142. if (mMinimum.x > b2.mMaximum.x)
  143. return false;
  144. if (mMinimum.y > b2.mMaximum.y)
  145. return false;
  146. if (mMinimum.z > b2.mMaximum.z)
  147. return false;
  148. // Otherwise, must be intersecting
  149. return true;
  150. }
  151. bool AABox::intersects(const Sphere& sphere) const
  152. {
  153. // Use splitting planes
  154. const Vector3& center = sphere.getCenter();
  155. float radius = sphere.getRadius();
  156. const Vector3& min = getMin();
  157. const Vector3& max = getMax();
  158. // Arvo's algorithm
  159. float s, d = 0;
  160. for (int i = 0; i < 3; ++i)
  161. {
  162. if (center[i] < min[i])
  163. {
  164. s = center[i] - min[i];
  165. d += s * s;
  166. }
  167. else if(center[i] > max[i])
  168. {
  169. s = center[i] - max[i];
  170. d += s * s;
  171. }
  172. }
  173. return d <= radius * radius;
  174. }
  175. bool AABox::intersects(const Plane& p) const
  176. {
  177. return (p.getSide(*this) == Plane::BOTH_SIDE);
  178. }
  179. std::pair<bool, float> AABox::intersects(const Ray& ray) const
  180. {
  181. float lowt = 0.0f;
  182. float t;
  183. bool hit = false;
  184. Vector3 hitpoint;
  185. const Vector3& min = getMin();
  186. const Vector3& max = getMax();
  187. const Vector3& rayorig = ray.getOrigin();
  188. const Vector3& raydir = ray.getDirection();
  189. // Check origin inside first
  190. if ((rayorig.x > min.x && rayorig.y > min.y && rayorig.z > min.z) && (rayorig.x < max.x && rayorig.y < max.y && rayorig.z < max.z))
  191. {
  192. return std::pair<bool, float>(true, 0.0f);
  193. }
  194. // Check each face in turn, only check closest 3
  195. // Min x
  196. if (rayorig.x <= min.x && raydir.x > 0)
  197. {
  198. t = (min.x - rayorig.x) / raydir.x;
  199. if (t >= 0)
  200. {
  201. // Substitute t back into ray and check bounds and dist
  202. hitpoint = rayorig + raydir * t;
  203. if (hitpoint.y >= min.y && hitpoint.y <= max.y &&
  204. hitpoint.z >= min.z && hitpoint.z <= max.z &&
  205. (!hit || t < lowt))
  206. {
  207. hit = true;
  208. lowt = t;
  209. }
  210. }
  211. }
  212. // Max x
  213. if (rayorig.x >= max.x && raydir.x < 0)
  214. {
  215. t = (max.x - rayorig.x) / raydir.x;
  216. if (t >= 0)
  217. {
  218. // Substitute t back into ray and check bounds and dist
  219. hitpoint = rayorig + raydir * t;
  220. if (hitpoint.y >= min.y && hitpoint.y <= max.y &&
  221. hitpoint.z >= min.z && hitpoint.z <= max.z &&
  222. (!hit || t < lowt))
  223. {
  224. hit = true;
  225. lowt = t;
  226. }
  227. }
  228. }
  229. // Min y
  230. if (rayorig.y <= min.y && raydir.y > 0)
  231. {
  232. t = (min.y - rayorig.y) / raydir.y;
  233. if (t >= 0)
  234. {
  235. // Substitute t back into ray and check bounds and dist
  236. hitpoint = rayorig + raydir * t;
  237. if (hitpoint.x >= min.x && hitpoint.x <= max.x &&
  238. hitpoint.z >= min.z && hitpoint.z <= max.z &&
  239. (!hit || t < lowt))
  240. {
  241. hit = true;
  242. lowt = t;
  243. }
  244. }
  245. }
  246. // Max y
  247. if (rayorig.y >= max.y && raydir.y < 0)
  248. {
  249. t = (max.y - rayorig.y) / raydir.y;
  250. if (t >= 0)
  251. {
  252. // Substitute t back into ray and check bounds and dist
  253. hitpoint = rayorig + raydir * t;
  254. if (hitpoint.x >= min.x && hitpoint.x <= max.x &&
  255. hitpoint.z >= min.z && hitpoint.z <= max.z &&
  256. (!hit || t < lowt))
  257. {
  258. hit = true;
  259. lowt = t;
  260. }
  261. }
  262. }
  263. // Min z
  264. if (rayorig.z <= min.z && raydir.z > 0)
  265. {
  266. t = (min.z - rayorig.z) / raydir.z;
  267. if (t >= 0)
  268. {
  269. // Substitute t back into ray and check bounds and dist
  270. hitpoint = rayorig + raydir * t;
  271. if (hitpoint.x >= min.x && hitpoint.x <= max.x &&
  272. hitpoint.y >= min.y && hitpoint.y <= max.y &&
  273. (!hit || t < lowt))
  274. {
  275. hit = true;
  276. lowt = t;
  277. }
  278. }
  279. }
  280. // Max z
  281. if (rayorig.z >= max.z && raydir.z < 0)
  282. {
  283. t = (max.z - rayorig.z) / raydir.z;
  284. if (t >= 0)
  285. {
  286. // Substitute t back into ray and check bounds and dist
  287. hitpoint = rayorig + raydir * t;
  288. if (hitpoint.x >= min.x && hitpoint.x <= max.x &&
  289. hitpoint.y >= min.y && hitpoint.y <= max.y &&
  290. (!hit || t < lowt))
  291. {
  292. hit = true;
  293. lowt = t;
  294. }
  295. }
  296. }
  297. return std::pair<bool, float>(hit, lowt);
  298. }
  299. bool AABox::intersects(const Ray& ray, float& d1, float& d2) const
  300. {
  301. const Vector3& min = getMin();
  302. const Vector3& max = getMax();
  303. const Vector3& rayorig = ray.getOrigin();
  304. const Vector3& raydir = ray.getDirection();
  305. Vector3 absDir;
  306. absDir[0] = Math::abs(raydir[0]);
  307. absDir[1] = Math::abs(raydir[1]);
  308. absDir[2] = Math::abs(raydir[2]);
  309. // Sort the axis, ensure check minimise floating error axis first
  310. int imax = 0, imid = 1, imin = 2;
  311. if (absDir[0] < absDir[2])
  312. {
  313. imax = 2;
  314. imin = 0;
  315. }
  316. if (absDir[1] < absDir[imin])
  317. {
  318. imid = imin;
  319. imin = 1;
  320. }
  321. else if (absDir[1] > absDir[imax])
  322. {
  323. imid = imax;
  324. imax = 1;
  325. }
  326. float start = 0, end = Math::POS_INFINITY;
  327. #define _CALC_AXIS(i) \
  328. do { \
  329. float denom = 1 / raydir[i]; \
  330. float newstart = (min[i] - rayorig[i]) * denom; \
  331. float newend = (max[i] - rayorig[i]) * denom; \
  332. if (newstart > newend) std::swap(newstart, newend); \
  333. if (newstart > end || newend < start) return false; \
  334. if (newstart > start) start = newstart; \
  335. if (newend < end) end = newend; \
  336. } while(0)
  337. // Check each axis in turn
  338. _CALC_AXIS(imax);
  339. if (absDir[imid] < std::numeric_limits<float>::epsilon())
  340. {
  341. // Parallel with middle and minimise axis, check bounds only
  342. if (rayorig[imid] < min[imid] || rayorig[imid] > max[imid] ||
  343. rayorig[imin] < min[imin] || rayorig[imin] > max[imin])
  344. return false;
  345. }
  346. else
  347. {
  348. _CALC_AXIS(imid);
  349. if (absDir[imin] < std::numeric_limits<float>::epsilon())
  350. {
  351. // Parallel with minimise axis, check bounds only
  352. if (rayorig[imin] < min[imin] || rayorig[imin] > max[imin])
  353. return false;
  354. }
  355. else
  356. {
  357. _CALC_AXIS(imin);
  358. }
  359. }
  360. #undef _CALC_AXIS
  361. d1 = start;
  362. d2 = end;
  363. return true;
  364. }
  365. Vector3 AABox::getCenter() const
  366. {
  367. return Vector3(
  368. (mMaximum.x + mMinimum.x) * 0.5f,
  369. (mMaximum.y + mMinimum.y) * 0.5f,
  370. (mMaximum.z + mMinimum.z) * 0.5f);
  371. }
  372. Vector3 AABox::getSize() const
  373. {
  374. return mMaximum - mMinimum;
  375. }
  376. Vector3 AABox::getHalfSize() const
  377. {
  378. return (mMaximum - mMinimum) * 0.5;
  379. }
  380. float AABox::getRadius() const
  381. {
  382. return (mMaximum - mMinimum).length();
  383. }
  384. float AABox::getVolume() const
  385. {
  386. Vector3 diff = mMaximum - mMinimum;
  387. return diff.x * diff.y * diff.z;
  388. }
  389. bool AABox::contains(const Vector3& v) const
  390. {
  391. return mMinimum.x <= v.x && v.x <= mMaximum.x &&
  392. mMinimum.y <= v.y && v.y <= mMaximum.y &&
  393. mMinimum.z <= v.z && v.z <= mMaximum.z;
  394. }
  395. bool AABox::contains(const AABox& other) const
  396. {
  397. return this->mMinimum.x <= other.mMinimum.x &&
  398. this->mMinimum.y <= other.mMinimum.y &&
  399. this->mMinimum.z <= other.mMinimum.z &&
  400. other.mMaximum.x <= this->mMaximum.x &&
  401. other.mMaximum.y <= this->mMaximum.y &&
  402. other.mMaximum.z <= this->mMaximum.z;
  403. }
  404. bool AABox::operator== (const AABox& rhs) const
  405. {
  406. return this->mMinimum == rhs.mMinimum &&
  407. this->mMaximum == rhs.mMaximum;
  408. }
  409. bool AABox::operator!= (const AABox& rhs) const
  410. {
  411. return !(*this == rhs);
  412. }
  413. }