OPC_LSSCollider.cpp 26 KB

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