BsAABox.cpp 11 KB

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