OPC_AABBCollider.cpp 26 KB

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