OPC_AABBCollider.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. /*
  3. * OPCODE - Optimized Collision Detection
  4. * Copyright (C) 2001 Pierre Terdiman
  5. * Homepage: http://www.codercorner.com/Opcode.htm
  6. */
  7. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  8. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  9. /**
  10. * Contains code for an AABB collider.
  11. * \file OPC_AABBCollider.cpp
  12. * \author Pierre Terdiman
  13. * \date January, 1st, 2002
  14. */
  15. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  16. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  17. /**
  18. * Contains an AABB-vs-tree collider.
  19. *
  20. * \class AABBCollider
  21. * \author Pierre Terdiman
  22. * \version 1.3
  23. * \date January, 1st, 2002
  24. */
  25. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  27. #include "Opcode.h"
  28. using namespace Opcode;
  29. #include "OPC_BoxBoxOverlap.h"
  30. #include "OPC_TriBoxOverlap.h"
  31. #define SET_CONTACT(prim_index, flag) \
  32. /* Set contact status */ \
  33. mFlags |= flag; \
  34. mTouchedPrimitives->Add(prim_index);
  35. //! AABB-triangle test
  36. #define AABB_PRIM(prim_index, flag) \
  37. /* Request vertices from the app */ \
  38. VertexPointers VP; mIMesh->GetTriangle(VP, prim_index);\
  39. mLeafVerts[0] = *VP.Vertex[0]; \
  40. mLeafVerts[1] = *VP.Vertex[1]; \
  41. mLeafVerts[2] = *VP.Vertex[2]; \
  42. /* Perform triangle-box overlap test */ \
  43. if(TriBoxOverlap()) \
  44. { \
  45. SET_CONTACT(prim_index, flag) \
  46. }
  47. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  48. /**
  49. * Constructor.
  50. */
  51. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  52. AABBCollider::AABBCollider()
  53. {
  54. }
  55. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  56. /**
  57. * Destructor.
  58. */
  59. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  60. AABBCollider::~AABBCollider()
  61. {
  62. }
  63. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  64. /**
  65. * Generic collision query for generic OPCODE models. After the call, access the results:
  66. * - with GetContactStatus()
  67. * - with GetNbTouchedPrimitives()
  68. * - with GetTouchedPrimitives()
  69. *
  70. * \param cache [in/out] a box cache
  71. * \param box [in] collision AABB in world space
  72. * \param model [in] Opcode model to collide with
  73. * \return true if success
  74. * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
  75. */
  76. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  77. bool AABBCollider::Collide(AABBCache& cache, const CollisionAABB& box, const Model& model)
  78. {
  79. // Checkings
  80. if(!Setup(&model)) return false;
  81. // Init collision query
  82. if(InitQuery(cache, box)) return true;
  83. if(!model.HasLeafNodes())
  84. {
  85. if(model.IsQuantized())
  86. {
  87. const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
  88. // Setup dequantization coeffs
  89. mCenterCoeff = Tree->mCenterCoeff;
  90. mExtentsCoeff = Tree->mExtentsCoeff;
  91. // Perform collision query
  92. if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes());
  93. else _Collide(Tree->GetNodes());
  94. }
  95. else
  96. {
  97. const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
  98. // Perform collision query
  99. if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes());
  100. else _Collide(Tree->GetNodes());
  101. }
  102. }
  103. else
  104. {
  105. if(model.IsQuantized())
  106. {
  107. const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
  108. // Setup dequantization coeffs
  109. mCenterCoeff = Tree->mCenterCoeff;
  110. mExtentsCoeff = Tree->mExtentsCoeff;
  111. // Perform collision query
  112. if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes());
  113. else _Collide(Tree->GetNodes());
  114. }
  115. else
  116. {
  117. const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
  118. // Perform collision query
  119. if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes());
  120. else _Collide(Tree->GetNodes());
  121. }
  122. }
  123. return true;
  124. }
  125. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  126. /**
  127. * Initializes a collision query :
  128. * - reset stats & contact status
  129. * - check temporal coherence
  130. *
  131. * \param cache [in/out] a box cache
  132. * \param box [in] AABB in world space
  133. * \return TRUE if we can return immediately
  134. */
  135. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  136. BOOL AABBCollider::InitQuery(AABBCache& cache, const CollisionAABB& box)
  137. {
  138. // 1) Call the base method
  139. VolumeCollider::InitQuery();
  140. // 2) Keep track of the query box
  141. mBox = box;
  142. // 3) Setup destination pointer
  143. mTouchedPrimitives = &cache.TouchedPrimitives;
  144. // 4) Special case: 1-triangle meshes [Opcode 1.3]
  145. if(mCurrentModel && mCurrentModel->HasSingleNode())
  146. {
  147. if(!SkipPrimitiveTests())
  148. {
  149. // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0.
  150. mTouchedPrimitives->Reset();
  151. // Perform overlap test between the unique triangle and the box (and set contact status if needed)
  152. AABB_PRIM(udword(0), OPC_CONTACT)
  153. // Return immediately regardless of status
  154. return TRUE;
  155. }
  156. }
  157. // 5) Check temporal coherence :
  158. if(TemporalCoherenceEnabled())
  159. {
  160. // Here we use temporal coherence
  161. // => check results from previous frame before performing the collision query
  162. if(FirstContactEnabled())
  163. {
  164. // We're only interested in the first contact found => test the unique previously touched face
  165. if(mTouchedPrimitives->GetNbEntries())
  166. {
  167. // Get index of previously touched face = the first entry in the array
  168. udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0);
  169. // Then reset the array:
  170. // - if the overlap test below is successful, the index we'll get added back anyway
  171. // - if it isn't, then the array should be reset anyway for the normal query
  172. mTouchedPrimitives->Reset();
  173. // Perform overlap test between the cached triangle and the box (and set contact status if needed)
  174. AABB_PRIM(PreviouslyTouchedFace, OPC_TEMPORAL_CONTACT)
  175. // Return immediately if possible
  176. if(GetContactStatus()) return TRUE;
  177. }
  178. // else no face has been touched during previous query
  179. // => we'll have to perform a normal query
  180. }
  181. else
  182. {
  183. // We're interested in all contacts =>test the new real box N(ew) against the previous fat box P(revious):
  184. if(IsCacheValid(cache) && mBox.IsInside(cache.FatBox))
  185. {
  186. // - if N is included in P, return previous list
  187. // => we simply leave the list (mTouchedFaces) unchanged
  188. // Set contact status if needed
  189. if(mTouchedPrimitives->GetNbEntries()) mFlags |= OPC_TEMPORAL_CONTACT;
  190. // In any case we don't need to do a query
  191. return TRUE;
  192. }
  193. else
  194. {
  195. // - else do the query using a fat N
  196. // Reset cache since we'll about to perform a real query
  197. mTouchedPrimitives->Reset();
  198. // Make a fat box so that coherence will work for subsequent frames
  199. mBox.mExtents *= cache.FatCoeff;
  200. // Update cache with query data (signature for cached faces)
  201. cache.FatBox = mBox;
  202. }
  203. }
  204. }
  205. else
  206. {
  207. // Here we don't use temporal coherence => do a normal query
  208. mTouchedPrimitives->Reset();
  209. }
  210. // 5) Precompute min & max bounds if needed
  211. mMin = box.mCenter - box.mExtents;
  212. mMax = box.mCenter + box.mExtents;
  213. return FALSE;
  214. }
  215. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  216. /**
  217. * Collision query for vanilla AABB trees.
  218. * \param cache [in/out] a box cache
  219. * \param box [in] collision AABB in world space
  220. * \param tree [in] AABB tree
  221. * \return true if success
  222. */
  223. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  224. bool AABBCollider::Collide(AABBCache& cache, const CollisionAABB& box, const AABBTree* tree)
  225. {
  226. // This is typically called for a scene tree, full of -AABBs-, not full of triangles.
  227. // So we don't really have "primitives" to deal with. Hence it doesn't work with
  228. // "FirstContact" + "TemporalCoherence".
  229. ASSERT( !(FirstContactEnabled() && TemporalCoherenceEnabled()) );
  230. // Checkings
  231. if(!tree) return false;
  232. // Init collision query
  233. if(InitQuery(cache, box)) return true;
  234. // Perform collision query
  235. _Collide(tree);
  236. return true;
  237. }
  238. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  239. /**
  240. * Checks the AABB completely contains the box. In which case we can end the query sooner.
  241. * \param bc [in] box center
  242. * \param be [in] box extents
  243. * \return true if the AABB contains the whole box
  244. */
  245. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  246. inline_ BOOL AABBCollider::AABBContainsBox(const Point& bc, const Point& be)
  247. {
  248. if(mMin.x > bc.x - be.x) return FALSE;
  249. if(mMin.y > bc.y - be.y) return FALSE;
  250. if(mMin.z > bc.z - be.z) return FALSE;
  251. if(mMax.x < bc.x + be.x) return FALSE;
  252. if(mMax.y < bc.y + be.y) return FALSE;
  253. if(mMax.z < bc.z + be.z) return FALSE;
  254. return TRUE;
  255. }
  256. #define TEST_BOX_IN_AABB(center, extents) \
  257. if(AABBContainsBox(center, extents)) \
  258. { \
  259. /* Set contact status */ \
  260. mFlags |= OPC_CONTACT; \
  261. _Dump(node); \
  262. return; \
  263. }
  264. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  265. /**
  266. * Recursive collision query for normal AABB trees.
  267. * \param node [in] current collision node
  268. */
  269. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  270. void AABBCollider::_Collide(const AABBCollisionNode* node)
  271. {
  272. // Perform AABB-AABB overlap test
  273. if(!AABBAABBOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return;
  274. TEST_BOX_IN_AABB(node->mAABB.mCenter, node->mAABB.mExtents)
  275. if(node->IsLeaf())
  276. {
  277. AABB_PRIM(node->GetPrimitive(), OPC_CONTACT)
  278. }
  279. else
  280. {
  281. _Collide(node->GetPos());
  282. if(ContactFound()) return;
  283. _Collide(node->GetNeg());
  284. }
  285. }
  286. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  287. /**
  288. * Recursive collision query for normal AABB trees, without primitive tests.
  289. * \param node [in] current collision node
  290. */
  291. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  292. void AABBCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node)
  293. {
  294. // Perform AABB-AABB overlap test
  295. if(!AABBAABBOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return;
  296. TEST_BOX_IN_AABB(node->mAABB.mCenter, node->mAABB.mExtents)
  297. if(node->IsLeaf())
  298. {
  299. SET_CONTACT(node->GetPrimitive(), OPC_CONTACT)
  300. }
  301. else
  302. {
  303. _CollideNoPrimitiveTest(node->GetPos());
  304. if(ContactFound()) return;
  305. _CollideNoPrimitiveTest(node->GetNeg());
  306. }
  307. }
  308. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  309. /**
  310. * Recursive collision query for quantized AABB trees.
  311. * \param node [in] current collision node
  312. */
  313. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  314. void AABBCollider::_Collide(const AABBQuantizedNode* node)
  315. {
  316. // Dequantize box
  317. const QuantizedAABB& Box = node->mAABB;
  318. const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
  319. const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
  320. // Perform AABB-AABB overlap test
  321. if(!AABBAABBOverlap(Extents, Center)) return;
  322. TEST_BOX_IN_AABB(Center, Extents)
  323. if(node->IsLeaf())
  324. {
  325. AABB_PRIM(node->GetPrimitive(), OPC_CONTACT)
  326. }
  327. else
  328. {
  329. _Collide(node->GetPos());
  330. if(ContactFound()) return;
  331. _Collide(node->GetNeg());
  332. }
  333. }
  334. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  335. /**
  336. * Recursive collision query for quantized AABB trees, without primitive tests.
  337. * \param node [in] current collision node
  338. */
  339. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  340. void AABBCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node)
  341. {
  342. // Dequantize box
  343. const QuantizedAABB& Box = node->mAABB;
  344. const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
  345. const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
  346. // Perform AABB-AABB overlap test
  347. if(!AABBAABBOverlap(Extents, Center)) return;
  348. TEST_BOX_IN_AABB(Center, Extents)
  349. if(node->IsLeaf())
  350. {
  351. SET_CONTACT(node->GetPrimitive(), OPC_CONTACT)
  352. }
  353. else
  354. {
  355. _CollideNoPrimitiveTest(node->GetPos());
  356. if(ContactFound()) return;
  357. _CollideNoPrimitiveTest(node->GetNeg());
  358. }
  359. }
  360. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  361. /**
  362. * Recursive collision query for no-leaf AABB trees.
  363. * \param node [in] current collision node
  364. */
  365. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  366. void AABBCollider::_Collide(const AABBNoLeafNode* node)
  367. {
  368. // Perform AABB-AABB overlap test
  369. if(!AABBAABBOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return;
  370. TEST_BOX_IN_AABB(node->mAABB.mCenter, node->mAABB.mExtents)
  371. if(node->HasPosLeaf()) { AABB_PRIM(node->GetPosPrimitive(), OPC_CONTACT) }
  372. else _Collide(node->GetPos());
  373. if(ContactFound()) return;
  374. if(node->HasNegLeaf()) { AABB_PRIM(node->GetNegPrimitive(), OPC_CONTACT) }
  375. else _Collide(node->GetNeg());
  376. }
  377. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  378. /**
  379. * Recursive collision query for no-leaf AABB trees, without primitive tests.
  380. * \param node [in] current collision node
  381. */
  382. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  383. void AABBCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node)
  384. {
  385. // Perform AABB-AABB overlap test
  386. if(!AABBAABBOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return;
  387. TEST_BOX_IN_AABB(node->mAABB.mCenter, node->mAABB.mExtents)
  388. if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) }
  389. else _CollideNoPrimitiveTest(node->GetPos());
  390. if(ContactFound()) return;
  391. if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) }
  392. else _CollideNoPrimitiveTest(node->GetNeg());
  393. }
  394. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  395. /**
  396. * Recursive collision query for quantized no-leaf AABB trees.
  397. * \param node [in] current collision node
  398. */
  399. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  400. void AABBCollider::_Collide(const AABBQuantizedNoLeafNode* node)
  401. {
  402. // Dequantize box
  403. const QuantizedAABB& Box = node->mAABB;
  404. const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
  405. const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
  406. // Perform AABB-AABB overlap test
  407. if(!AABBAABBOverlap(Extents, Center)) return;
  408. TEST_BOX_IN_AABB(Center, Extents)
  409. if(node->HasPosLeaf()) { AABB_PRIM(node->GetPosPrimitive(), OPC_CONTACT) }
  410. else _Collide(node->GetPos());
  411. if(ContactFound()) return;
  412. if(node->HasNegLeaf()) { AABB_PRIM(node->GetNegPrimitive(), OPC_CONTACT) }
  413. else _Collide(node->GetNeg());
  414. }
  415. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  416. /**
  417. * Recursive collision query for quantized no-leaf AABB trees, without primitive tests.
  418. * \param node [in] current collision node
  419. */
  420. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  421. void AABBCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node)
  422. {
  423. // Dequantize box
  424. const QuantizedAABB& Box = node->mAABB;
  425. const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
  426. const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
  427. // Perform AABB-AABB overlap test
  428. if(!AABBAABBOverlap(Extents, Center)) return;
  429. TEST_BOX_IN_AABB(Center, Extents)
  430. if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) }
  431. else _CollideNoPrimitiveTest(node->GetPos());
  432. if(ContactFound()) return;
  433. if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) }
  434. else _CollideNoPrimitiveTest(node->GetNeg());
  435. }
  436. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  437. /**
  438. * Recursive collision query for vanilla AABB trees.
  439. * \param node [in] current collision node
  440. */
  441. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  442. void AABBCollider::_Collide(const AABBTreeNode* node)
  443. {
  444. // Perform AABB-AABB overlap test
  445. Point Center, Extents;
  446. node->GetAABB()->GetCenter(Center);
  447. node->GetAABB()->GetExtents(Extents);
  448. if(!AABBAABBOverlap(Center, Extents)) return;
  449. if(node->IsLeaf() || AABBContainsBox(Center, Extents))
  450. {
  451. mFlags |= OPC_CONTACT;
  452. mTouchedPrimitives->Add(node->GetPrimitives(), node->GetNbPrimitives());
  453. }
  454. else
  455. {
  456. _Collide(node->GetPos());
  457. _Collide(node->GetNeg());
  458. }
  459. }
  460. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  461. /**
  462. * Constructor.
  463. */
  464. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  465. HybridAABBCollider::HybridAABBCollider()
  466. {
  467. }
  468. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  469. /**
  470. * Destructor.
  471. */
  472. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  473. HybridAABBCollider::~HybridAABBCollider()
  474. {
  475. }
  476. bool HybridAABBCollider::Collide(AABBCache& cache, const CollisionAABB& box, const HybridModel& model)
  477. {
  478. // We don't want primitive tests here!
  479. mFlags |= OPC_NO_PRIMITIVE_TESTS;
  480. // Checkings
  481. if(!Setup(&model)) return false;
  482. // Init collision query
  483. if(InitQuery(cache, box)) return true;
  484. // Special case for 1-leaf trees
  485. if(mCurrentModel && mCurrentModel->HasSingleNode())
  486. {
  487. // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles
  488. udword Nb = mIMesh->GetNbTriangles();
  489. // Loop through all triangles
  490. for(udword i=0;i<Nb;i++)
  491. {
  492. AABB_PRIM(i, OPC_CONTACT)
  493. }
  494. return true;
  495. }
  496. // Override destination array since we're only going to get leaf boxes here
  497. mTouchedBoxes.Reset();
  498. mTouchedPrimitives = &mTouchedBoxes;
  499. // Now, do the actual query against leaf boxes
  500. if(!model.HasLeafNodes())
  501. {
  502. if(model.IsQuantized())
  503. {
  504. const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
  505. // Setup dequantization coeffs
  506. mCenterCoeff = Tree->mCenterCoeff;
  507. mExtentsCoeff = Tree->mExtentsCoeff;
  508. // Perform collision query - we don't want primitive tests here!
  509. _CollideNoPrimitiveTest(Tree->GetNodes());
  510. }
  511. else
  512. {
  513. const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
  514. // Perform collision query - we don't want primitive tests here!
  515. _CollideNoPrimitiveTest(Tree->GetNodes());
  516. }
  517. }
  518. else
  519. {
  520. if(model.IsQuantized())
  521. {
  522. const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
  523. // Setup dequantization coeffs
  524. mCenterCoeff = Tree->mCenterCoeff;
  525. mExtentsCoeff = Tree->mExtentsCoeff;
  526. // Perform collision query - we don't want primitive tests here!
  527. _CollideNoPrimitiveTest(Tree->GetNodes());
  528. }
  529. else
  530. {
  531. const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
  532. // Perform collision query - we don't want primitive tests here!
  533. _CollideNoPrimitiveTest(Tree->GetNodes());
  534. }
  535. }
  536. // We only have a list of boxes so far
  537. if(GetContactStatus())
  538. {
  539. // Reset contact status, since it currently only reflects collisions with leaf boxes
  540. Collider::InitQuery();
  541. // Change dest container so that we can use built-in overlap tests and get collided primitives
  542. cache.TouchedPrimitives.Reset();
  543. mTouchedPrimitives = &cache.TouchedPrimitives;
  544. // Read touched leaf boxes
  545. udword Nb = mTouchedBoxes.GetNbEntries();
  546. const udword* Touched = mTouchedBoxes.GetEntries();
  547. const LeafTriangles* LT = model.GetLeafTriangles();
  548. const udword* Indices = model.GetIndices();
  549. // Loop through touched leaves
  550. while(Nb--)
  551. {
  552. const LeafTriangles& CurrentLeaf = LT[*Touched++];
  553. // Each leaf box has a set of triangles
  554. udword NbTris = CurrentLeaf.GetNbTriangles();
  555. if(Indices)
  556. {
  557. const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()];
  558. // Loop through triangles and test each of them
  559. while(NbTris--)
  560. {
  561. udword TriangleIndex = *T++;
  562. AABB_PRIM(TriangleIndex, OPC_CONTACT)
  563. }
  564. }
  565. else
  566. {
  567. udword BaseIndex = CurrentLeaf.GetTriangleIndex();
  568. // Loop through triangles and test each of them
  569. while(NbTris--)
  570. {
  571. udword TriangleIndex = BaseIndex++;
  572. AABB_PRIM(TriangleIndex, OPC_CONTACT)
  573. }
  574. }
  575. }
  576. }
  577. return true;
  578. }