CmAABox.cpp 12 KB

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