OPC_RayCollider.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  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 a ray collider.
  11. * \file OPC_RayCollider.cpp
  12. * \author Pierre Terdiman
  13. * \date June, 2, 2001
  14. */
  15. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  16. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  17. /**
  18. * Contains a ray-vs-tree collider.
  19. * This class performs a stabbing query on an AABB tree, i.e. does a ray-mesh collision.
  20. *
  21. * HIGHER DISTANCE BOUND:
  22. *
  23. * If P0 and P1 are two 3D points, let's define:
  24. * - d = distance between P0 and P1
  25. * - Origin = P0
  26. * - Direction = (P1 - P0) / d = normalized direction vector
  27. * - A parameter t such as a point P on the line (P0,P1) is P = Origin + t * Direction
  28. * - t = 0 --> P = P0
  29. * - t = d --> P = P1
  30. *
  31. * Then we can define a general "ray" as:
  32. *
  33. * struct Ray
  34. * {
  35. * Point Origin;
  36. * Point Direction;
  37. * };
  38. *
  39. * But it actually maps three different things:
  40. * - a segment, when 0 <= t <= d
  41. * - a half-line, when 0 <= t < +infinity, or -infinity < t <= d
  42. * - a line, when -infinity < t < +infinity
  43. *
  44. * In Opcode, we support segment queries, which yield half-line queries by setting d = +infinity.
  45. * We don't support line-queries. If you need them, shift the origin along the ray by an appropriate margin.
  46. *
  47. * In short, the lower bound is always 0, and you can setup the higher bound "d" with RayCollider::SetMaxDist().
  48. *
  49. * Query |segment |half-line |line
  50. * --------|-------------------|---------------|----------------
  51. * Usages |-shadow feelers |-raytracing |-
  52. * |-sweep tests |-in/out tests |
  53. *
  54. * FIRST CONTACT:
  55. *
  56. * - You can setup "first contact" mode or "all contacts" mode with RayCollider::SetFirstContact().
  57. * - In "first contact" mode we return as soon as the ray hits one face. If can be useful e.g. for shadow feelers, where
  58. * you want to know whether the path to the light is free or not (a boolean answer is enough).
  59. * - In "all contacts" mode we return all faces hit by the ray.
  60. *
  61. * TEMPORAL COHERENCE:
  62. *
  63. * - You can enable or disable temporal coherence with RayCollider::SetTemporalCoherence().
  64. * - It currently only works in "first contact" mode.
  65. * - If temporal coherence is enabled, the previously hit triangle is cached during the first query. Then, next queries
  66. * start by colliding the ray against the cached triangle. If they still collide, we return immediately.
  67. *
  68. * CLOSEST HIT:
  69. *
  70. * - You can enable or disable "closest hit" with RayCollider::SetClosestHit().
  71. * - It currently only works in "all contacts" mode.
  72. * - If closest hit is enabled, faces are sorted by distance on-the-fly and the closest one only is reported.
  73. *
  74. * BACKFACE CULLING:
  75. *
  76. * - You can enable or disable backface culling with RayCollider::SetCulling().
  77. * - If culling is enabled, ray will not hit back faces (only front faces).
  78. *
  79. *
  80. *
  81. * \class RayCollider
  82. * \author Pierre Terdiman
  83. * \version 1.3
  84. * \date June, 2, 2001
  85. */
  86. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  87. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  88. /**
  89. * This class describes a face hit by a ray or segment.
  90. * This is a particular class dedicated to stabbing queries.
  91. *
  92. * \class CollisionFace
  93. * \author Pierre Terdiman
  94. * \version 1.3
  95. * \date March, 20, 2001
  96. */
  97. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  98. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  99. /**
  100. * This class is a dedicated collection of CollisionFace.
  101. *
  102. * \class CollisionFaces
  103. * \author Pierre Terdiman
  104. * \version 1.3
  105. * \date March, 20, 2001
  106. */
  107. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  108. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  109. // Precompiled Header
  110. #include "Stdafx.h"
  111. using namespace Opcode;
  112. #include "OPC_RayAABBOverlap.h"
  113. #include "OPC_RayTriOverlap.h"
  114. #define SET_CONTACT(prim_index, flag) \
  115. mNbIntersections++; \
  116. /* Set contact status */ \
  117. mFlags |= flag; \
  118. /* In any case the contact has been found and recorded in mStabbedFace */ \
  119. mStabbedFace.mFaceID = prim_index;
  120. #ifdef OPC_RAYHIT_CALLBACK
  121. #define HANDLE_CONTACT(prim_index, flag) \
  122. SET_CONTACT(prim_index, flag) \
  123. \
  124. if(mHitCallback) (mHitCallback)(mStabbedFace, mUserData);
  125. #define UPDATE_CACHE \
  126. if(cache && GetContactStatus()) \
  127. { \
  128. *cache = mStabbedFace.mFaceID; \
  129. }
  130. #else
  131. #define HANDLE_CONTACT(prim_index, flag) \
  132. SET_CONTACT(prim_index, flag) \
  133. \
  134. /* Now we can also record it in mStabbedFaces if available */ \
  135. if(mStabbedFaces) \
  136. { \
  137. /* If we want all faces or if that's the first one we hit */ \
  138. if(!mClosestHit || !mStabbedFaces->GetNbFaces()) \
  139. { \
  140. mStabbedFaces->AddFace(mStabbedFace); \
  141. } \
  142. else \
  143. { \
  144. /* We only keep closest hit */ \
  145. CollisionFace* Current = const_cast<CollisionFace*>(mStabbedFaces->GetFaces()); \
  146. if(Current && mStabbedFace.mDistance<Current->mDistance) \
  147. { \
  148. *Current = mStabbedFace; \
  149. } \
  150. } \
  151. }
  152. #define UPDATE_CACHE \
  153. if(cache && GetContactStatus() && mStabbedFaces) \
  154. { \
  155. const CollisionFace* Current = mStabbedFaces->GetFaces(); \
  156. if(Current) *cache = Current->mFaceID; \
  157. else *cache = INVALID_ID; \
  158. }
  159. #endif
  160. #define SEGMENT_PRIM(prim_index, flag) \
  161. /* Request vertices from the app */ \
  162. VertexPointers VP; ConversionArea VC; mIMesh->GetTriangle(VP, prim_index, VC); \
  163. \
  164. /* Perform ray-tri overlap test and return */ \
  165. if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \
  166. { \
  167. /* Intersection point is valid if dist < segment's length */ \
  168. /* We know dist>0 so we can use integers */ \
  169. if(IR(mStabbedFace.mDistance)<IR(mMaxDist)) \
  170. { \
  171. HANDLE_CONTACT(prim_index, flag) \
  172. } \
  173. }
  174. #define RAY_PRIM(prim_index, flag) \
  175. /* Request vertices from the app */ \
  176. VertexPointers VP; ConversionArea VC; mIMesh->GetTriangle(VP, prim_index, VC); \
  177. \
  178. /* Perform ray-tri overlap test and return */ \
  179. if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \
  180. { \
  181. HANDLE_CONTACT(prim_index, flag) \
  182. }
  183. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  184. /**
  185. * Constructor.
  186. */
  187. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  188. RayCollider::RayCollider() :
  189. #ifdef OPC_RAYHIT_CALLBACK
  190. mHitCallback (null),
  191. mUserData (0),
  192. #else
  193. mStabbedFaces (null),
  194. mClosestHit (false),
  195. #endif
  196. mNbRayBVTests (0),
  197. mNbRayPrimTests (0),
  198. mNbIntersections (0),
  199. mMaxDist (MAX_FLOAT),
  200. mCulling (true)
  201. {
  202. }
  203. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  204. /**
  205. * Destructor.
  206. */
  207. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  208. RayCollider::~RayCollider()
  209. {
  210. }
  211. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  212. /**
  213. * Validates current settings. You should call this method after all the settings and callbacks have been defined.
  214. * \return null if everything is ok, else a string describing the problem
  215. */
  216. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  217. const char* RayCollider::ValidateSettings()
  218. {
  219. if(mMaxDist<0.0f) return "Higher distance bound must be positive!";
  220. if(TemporalCoherenceEnabled() && !FirstContactEnabled()) return "Temporal coherence only works with ""First contact"" mode!";
  221. #ifndef OPC_RAYHIT_CALLBACK
  222. if(mClosestHit && FirstContactEnabled()) return "Closest hit doesn't work with ""First contact"" mode!";
  223. if(TemporalCoherenceEnabled() && mClosestHit) return "Temporal coherence can't guarantee to report closest hit!";
  224. #endif
  225. if(SkipPrimitiveTests()) return "SkipPrimitiveTests not possible for RayCollider ! (not implemented)";
  226. return null;
  227. }
  228. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  229. /**
  230. * Generic stabbing query for generic OPCODE models. After the call, access the results:
  231. * - with GetContactStatus()
  232. * - in the user-provided destination array
  233. *
  234. * \param world_ray [in] stabbing ray in world space
  235. * \param model [in] Opcode model to collide with
  236. * \param world [in] model's world matrix, or null
  237. * \param cache [in] a possibly cached face index, or null
  238. * \return true if success
  239. * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
  240. */
  241. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  242. bool RayCollider::Collide(const Ray& world_ray, const Model& model, const Matrix4x4* world, udword* cache)
  243. {
  244. // Checkings
  245. if(!Setup(&model)) return false;
  246. // Init collision query
  247. if(InitQuery(world_ray, world, cache)) return true;
  248. if(!model.HasLeafNodes())
  249. {
  250. if(model.IsQuantized())
  251. {
  252. const AABBQuantizedNoLeafTree* Tree = static_cast<const AABBQuantizedNoLeafTree *>(model.GetTree());
  253. // Setup dequantization coeffs
  254. mCenterCoeff = Tree->mCenterCoeff;
  255. mExtentsCoeff = Tree->mExtentsCoeff;
  256. // Perform stabbing query
  257. if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes());
  258. else _RayStab(Tree->GetNodes());
  259. }
  260. else
  261. {
  262. const AABBNoLeafTree* Tree = static_cast<const AABBNoLeafTree *>(model.GetTree());
  263. // Perform stabbing query
  264. if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes());
  265. else _RayStab(Tree->GetNodes());
  266. }
  267. }
  268. else
  269. {
  270. if(model.IsQuantized())
  271. {
  272. const AABBQuantizedTree* Tree = static_cast<const AABBQuantizedTree *>(model.GetTree());
  273. // Setup dequantization coeffs
  274. mCenterCoeff = Tree->mCenterCoeff;
  275. mExtentsCoeff = Tree->mExtentsCoeff;
  276. // Perform stabbing query
  277. if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes());
  278. else _RayStab(Tree->GetNodes());
  279. }
  280. else
  281. {
  282. const AABBCollisionTree* Tree = static_cast<const AABBCollisionTree *>(model.GetTree());
  283. // Perform stabbing query
  284. if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes());
  285. else _RayStab(Tree->GetNodes());
  286. }
  287. }
  288. // Update cache if needed
  289. UPDATE_CACHE;
  290. return true;
  291. }
  292. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  293. /**
  294. * Initializes a stabbing query :
  295. * - reset stats & contact status
  296. * - compute ray in local space
  297. * - check temporal coherence
  298. *
  299. * \param world_ray [in] stabbing ray in world space
  300. * \param world [in] object's world matrix, or null
  301. * \param face_id [in] index of previously stabbed triangle
  302. * \return TRUE if we can return immediately
  303. * \warning SCALE NOT SUPPORTED. The matrix must contain rotation & translation parts only.
  304. */
  305. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  306. BOOL RayCollider::InitQuery(const Ray& world_ray, const Matrix4x4* world, udword* face_id)
  307. {
  308. // Reset stats & contact status
  309. Collider::InitQuery();
  310. mNbRayBVTests = 0;
  311. mNbRayPrimTests = 0;
  312. mNbIntersections = 0;
  313. #ifndef OPC_RAYHIT_CALLBACK
  314. if(mStabbedFaces) mStabbedFaces->Reset();
  315. #endif
  316. // Compute ray in local space
  317. // The (Origin/Dir) form is needed for the ray-triangle test anyway (even for segment tests)
  318. if(world)
  319. {
  320. Matrix3x3 InvWorld = *world;
  321. mDir = InvWorld * world_ray.mDir;
  322. Matrix4x4 World;
  323. InvertPRMatrix(World, *world);
  324. mOrigin = world_ray.mOrig * World;
  325. }
  326. else
  327. {
  328. mDir = world_ray.mDir;
  329. mOrigin = world_ray.mOrig;
  330. }
  331. // 4) Special case: 1-triangle meshes [Opcode 1.3]
  332. if(mCurrentModel && mCurrentModel->HasSingleNode())
  333. {
  334. // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0.
  335. if(!SkipPrimitiveTests())
  336. {
  337. // Perform overlap test between the unique triangle and the ray (and set contact status if needed)
  338. SEGMENT_PRIM(udword(0), OPC_CONTACT)
  339. // Return immediately regardless of status
  340. return TRUE;
  341. }
  342. }
  343. // Check temporal coherence :
  344. // Test previously colliding primitives first
  345. if(TemporalCoherenceEnabled() && FirstContactEnabled() && face_id && *face_id!=INVALID_ID)
  346. {
  347. #ifdef OLD_CODE
  348. #ifndef OPC_RAYHIT_CALLBACK
  349. if(!mClosestHit)
  350. #endif
  351. {
  352. // Request vertices from the app
  353. VertexPointers VP;
  354. ConversionArea VC;
  355. mIMesh->GetTriangle(VP, *face_id, VC);
  356. // Perform ray-cached tri overlap test
  357. if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2]))
  358. {
  359. // Intersection point is valid if:
  360. // - distance is positive (else it can just be a face behind the orig point)
  361. // - distance is smaller than a given max distance (useful for shadow feelers)
  362. // if(mStabbedFace.mDistance>0.0f && mStabbedFace.mDistance<mMaxDist)
  363. if(IR(mStabbedFace.mDistance)<IR(mMaxDist)) // The other test is already performed in RayTriOverlap
  364. {
  365. // Set contact status
  366. mFlags |= OPC_TEMPORAL_CONTACT;
  367. mStabbedFace.mFaceID = *face_id;
  368. #ifndef OPC_RAYHIT_CALLBACK
  369. if(mStabbedFaces) mStabbedFaces->AddFace(mStabbedFace);
  370. #endif
  371. return TRUE;
  372. }
  373. }
  374. }
  375. #else
  376. // New code
  377. // We handle both Segment/ray queries with the same segment code, and a possible infinite limit
  378. SEGMENT_PRIM(*face_id, OPC_TEMPORAL_CONTACT)
  379. // Return immediately if possible
  380. if(GetContactStatus()) return TRUE;
  381. #endif
  382. }
  383. // Precompute data (moved after temporal coherence since only needed for ray-AABB)
  384. if(IR(mMaxDist)!=IEEE_MAX_FLOAT)
  385. {
  386. // For Segment-AABB overlap
  387. mData = 0.5f * mDir * mMaxDist;
  388. mData2 = mOrigin + mData;
  389. // Precompute mFDir;
  390. mFDir.x = fabsf(mData.x);
  391. mFDir.y = fabsf(mData.y);
  392. mFDir.z = fabsf(mData.z);
  393. }
  394. else
  395. {
  396. // For Ray-AABB overlap
  397. // udword x = SIR(mDir.x)-1;
  398. // udword y = SIR(mDir.y)-1;
  399. // udword z = SIR(mDir.z)-1;
  400. // mData.x = FR(x);
  401. // mData.y = FR(y);
  402. // mData.z = FR(z);
  403. // Precompute mFDir;
  404. mFDir.x = fabsf(mDir.x);
  405. mFDir.y = fabsf(mDir.y);
  406. mFDir.z = fabsf(mDir.z);
  407. }
  408. return FALSE;
  409. }
  410. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  411. /**
  412. * Stabbing query for vanilla AABB trees.
  413. * \param world_ray [in] stabbing ray in world space
  414. * \param tree [in] AABB tree
  415. * \param box_indices [out] indices of stabbed boxes
  416. * \return true if success
  417. */
  418. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  419. bool RayCollider::Collide(const Ray& world_ray, const AABBTree* tree, Container& box_indices)
  420. {
  421. // ### bad design here
  422. // This is typically called for a scene tree, full of -AABBs-, not full of triangles.
  423. // So we don't really have "primitives" to deal with. Hence it doesn't work with
  424. // "FirstContact" + "TemporalCoherence".
  425. ASSERT( !(FirstContactEnabled() && TemporalCoherenceEnabled()) );
  426. // Checkings
  427. if(!tree) return false;
  428. // Init collision query
  429. // Basically this is only called to initialize precomputed data
  430. if(InitQuery(world_ray)) return true;
  431. // Perform stabbing query
  432. if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(tree, box_indices);
  433. else _RayStab(tree, box_indices);
  434. return true;
  435. }
  436. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  437. /**
  438. * Recursive stabbing query for normal AABB trees.
  439. * \param node [in] current collision node
  440. */
  441. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  442. void RayCollider::_SegmentStab(const AABBCollisionNode* node)
  443. {
  444. // Perform Segment-AABB overlap test
  445. if(!SegmentAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
  446. if(node->IsLeaf())
  447. {
  448. SEGMENT_PRIM(node->GetPrimitive(), OPC_CONTACT)
  449. }
  450. else
  451. {
  452. _SegmentStab(node->GetPos());
  453. if(ContactFound()) return;
  454. _SegmentStab(node->GetNeg());
  455. }
  456. }
  457. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  458. /**
  459. * Recursive stabbing query for quantized AABB trees.
  460. * \param node [in] current collision node
  461. */
  462. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  463. void RayCollider::_SegmentStab(const AABBQuantizedNode* node)
  464. {
  465. // Dequantize box
  466. const QuantizedAABB& Box = node->mAABB;
  467. const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
  468. const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
  469. // Perform Segment-AABB overlap test
  470. if(!SegmentAABBOverlap(Center, Extents)) return;
  471. if(node->IsLeaf())
  472. {
  473. SEGMENT_PRIM(node->GetPrimitive(), OPC_CONTACT)
  474. }
  475. else
  476. {
  477. _SegmentStab(node->GetPos());
  478. if(ContactFound()) return;
  479. _SegmentStab(node->GetNeg());
  480. }
  481. }
  482. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  483. /**
  484. * Recursive stabbing query for no-leaf AABB trees.
  485. * \param node [in] current collision node
  486. */
  487. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  488. void RayCollider::_SegmentStab(const AABBNoLeafNode* node)
  489. {
  490. // Perform Segment-AABB overlap test
  491. if(!SegmentAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
  492. if(node->HasPosLeaf())
  493. {
  494. SEGMENT_PRIM(node->GetPosPrimitive(), OPC_CONTACT)
  495. }
  496. else _SegmentStab(node->GetPos());
  497. if(ContactFound()) return;
  498. if(node->HasNegLeaf())
  499. {
  500. SEGMENT_PRIM(node->GetNegPrimitive(), OPC_CONTACT)
  501. }
  502. else _SegmentStab(node->GetNeg());
  503. }
  504. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  505. /**
  506. * Recursive stabbing query for quantized no-leaf AABB trees.
  507. * \param node [in] current collision node
  508. */
  509. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  510. void RayCollider::_SegmentStab(const AABBQuantizedNoLeafNode* node)
  511. {
  512. // Dequantize box
  513. const QuantizedAABB& Box = node->mAABB;
  514. const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
  515. const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
  516. // Perform Segment-AABB overlap test
  517. if(!SegmentAABBOverlap(Center, Extents)) return;
  518. if(node->HasPosLeaf())
  519. {
  520. SEGMENT_PRIM(node->GetPosPrimitive(), OPC_CONTACT)
  521. }
  522. else _SegmentStab(node->GetPos());
  523. if(ContactFound()) return;
  524. if(node->HasNegLeaf())
  525. {
  526. SEGMENT_PRIM(node->GetNegPrimitive(), OPC_CONTACT)
  527. }
  528. else _SegmentStab(node->GetNeg());
  529. }
  530. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  531. /**
  532. * Recursive stabbing query for vanilla AABB trees.
  533. * \param node [in] current collision node
  534. * \param box_indices [out] indices of stabbed boxes
  535. */
  536. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  537. void RayCollider::_SegmentStab(const AABBTreeNode* node, Container& box_indices)
  538. {
  539. // Test the box against the segment
  540. Point Center, Extents;
  541. node->GetAABB()->GetCenter(Center);
  542. node->GetAABB()->GetExtents(Extents);
  543. if(!SegmentAABBOverlap(Center, Extents)) return;
  544. if(node->IsLeaf())
  545. {
  546. box_indices.Add(node->GetPrimitives(), node->GetNbPrimitives());
  547. }
  548. else
  549. {
  550. _SegmentStab(node->GetPos(), box_indices);
  551. _SegmentStab(node->GetNeg(), box_indices);
  552. }
  553. }
  554. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  555. /**
  556. * Recursive stabbing query for normal AABB trees.
  557. * \param node [in] current collision node
  558. */
  559. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  560. void RayCollider::_RayStab(const AABBCollisionNode* node)
  561. {
  562. // Perform Ray-AABB overlap test
  563. if(!RayAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
  564. if(node->IsLeaf())
  565. {
  566. RAY_PRIM(node->GetPrimitive(), OPC_CONTACT)
  567. }
  568. else
  569. {
  570. _RayStab(node->GetPos());
  571. if(ContactFound()) return;
  572. _RayStab(node->GetNeg());
  573. }
  574. }
  575. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  576. /**
  577. * Recursive stabbing query for quantized AABB trees.
  578. * \param node [in] current collision node
  579. */
  580. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  581. void RayCollider::_RayStab(const AABBQuantizedNode* node)
  582. {
  583. // Dequantize box
  584. const QuantizedAABB& Box = node->mAABB;
  585. const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
  586. const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
  587. // Perform Ray-AABB overlap test
  588. if(!RayAABBOverlap(Center, Extents)) return;
  589. if(node->IsLeaf())
  590. {
  591. RAY_PRIM(node->GetPrimitive(), OPC_CONTACT)
  592. }
  593. else
  594. {
  595. _RayStab(node->GetPos());
  596. if(ContactFound()) return;
  597. _RayStab(node->GetNeg());
  598. }
  599. }
  600. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  601. /**
  602. * Recursive stabbing query for no-leaf AABB trees.
  603. * \param node [in] current collision node
  604. */
  605. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  606. void RayCollider::_RayStab(const AABBNoLeafNode* node)
  607. {
  608. // Perform Ray-AABB overlap test
  609. if(!RayAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
  610. if(node->HasPosLeaf())
  611. {
  612. RAY_PRIM(node->GetPosPrimitive(), OPC_CONTACT)
  613. }
  614. else _RayStab(node->GetPos());
  615. if(ContactFound()) return;
  616. if(node->HasNegLeaf())
  617. {
  618. RAY_PRIM(node->GetNegPrimitive(), OPC_CONTACT)
  619. }
  620. else _RayStab(node->GetNeg());
  621. }
  622. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  623. /**
  624. * Recursive stabbing query for quantized no-leaf AABB trees.
  625. * \param node [in] current collision node
  626. */
  627. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  628. void RayCollider::_RayStab(const AABBQuantizedNoLeafNode* node)
  629. {
  630. // Dequantize box
  631. const QuantizedAABB& Box = node->mAABB;
  632. const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
  633. const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
  634. // Perform Ray-AABB overlap test
  635. if(!RayAABBOverlap(Center, Extents)) return;
  636. if(node->HasPosLeaf())
  637. {
  638. RAY_PRIM(node->GetPosPrimitive(), OPC_CONTACT)
  639. }
  640. else _RayStab(node->GetPos());
  641. if(ContactFound()) return;
  642. if(node->HasNegLeaf())
  643. {
  644. RAY_PRIM(node->GetNegPrimitive(), OPC_CONTACT)
  645. }
  646. else _RayStab(node->GetNeg());
  647. }
  648. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  649. /**
  650. * Recursive stabbing query for vanilla AABB trees.
  651. * \param node [in] current collision node
  652. * \param box_indices [out] indices of stabbed boxes
  653. */
  654. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  655. void RayCollider::_RayStab(const AABBTreeNode* node, Container& box_indices)
  656. {
  657. // Test the box against the ray
  658. Point Center, Extents;
  659. node->GetAABB()->GetCenter(Center);
  660. node->GetAABB()->GetExtents(Extents);
  661. if(!RayAABBOverlap(Center, Extents)) return;
  662. if(node->IsLeaf())
  663. {
  664. mFlags |= OPC_CONTACT;
  665. box_indices.Add(node->GetPrimitives(), node->GetNbPrimitives());
  666. }
  667. else
  668. {
  669. _RayStab(node->GetPos(), box_indices);
  670. _RayStab(node->GetNeg(), box_indices);
  671. }
  672. }