Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
OPC_LSSCollider.cpp
Go to the documentation of this file.
1 /*
3  * OPCODE - Optimized Collision Detection
4  * Copyright (C) 2001 Pierre Terdiman
5  * Homepage: http://www.codercorner.com/Opcode.htm
6  */
8 
10 
16 
19 
27 
30 // Precompiled Header
31 #include "Stdafx.h"
32 
33 
34 using namespace Opcode;
35 
36 #include "OPC_LSSAABBOverlap.h"
37 #include "OPC_LSSTriOverlap.h"
38 
39 #define SET_CONTACT(prim_index, flag) \
40  /* Set contact status */ \
41  mFlags |= flag; \
42  mTouchedPrimitives->Add(prim_index);
43 
45 #define LSS_PRIM(prim_index, flag) \
46  /* Request vertices from the app */ \
47  VertexPointers VP; mIMesh->GetTriangle(VP, prim_index); \
48  \
49  /* Perform LSS-tri overlap test */ \
50  if(LSSTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \
51  { \
52  SET_CONTACT(prim_index, flag) \
53  }
54 
56 
61 {
62 // mCenter.Zero();
63 // mRadius2 = 0.0f;
64 }
65 
67 
72 {
73 }
74 
76 
90 bool LSSCollider::Collide(LSSCache& cache, const LSS& lss, const Model& model, const Matrix4x4* worldl, const Matrix4x4* worldm)
92 {
93  // Checkings
94  if(!Setup(&model)) return false;
95 
96  // Init collision query
97  if(InitQuery(cache, lss, worldl, worldm)) return true;
98 
99  if(!model.HasLeafNodes())
100  {
101  if(model.IsQuantized())
102  {
103  const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
104 
105  // Setup dequantization coeffs
106  mCenterCoeff = Tree->mCenterCoeff;
108 
109  // Perform collision query
110  if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes());
111  else _Collide(Tree->GetNodes());
112  }
113  else
114  {
115  const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
116 
117  // Perform collision query
118  if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes());
119  else _Collide(Tree->GetNodes());
120  }
121  }
122  else
123  {
124  if(model.IsQuantized())
125  {
126  const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
127 
128  // Setup dequantization coeffs
129  mCenterCoeff = Tree->mCenterCoeff;
131 
132  // Perform collision query
133  if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes());
134  else _Collide(Tree->GetNodes());
135  }
136  else
137  {
138  const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
139 
140  // Perform collision query
141  if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes());
142  else _Collide(Tree->GetNodes());
143  }
144  }
145 
146  return true;
147 }
148 
150 
163 bool LSSCollider::InitQuery(LSSCache& cache, const LSS& lss, const Matrix4x4* worldl, const Matrix4x4* worldm)
165 {
166  // 1) Call the base method
168 
169  // 2) Compute LSS in model space:
170  // - Precompute R^2
171  mRadius2 = lss.mRadius * lss.mRadius;
172  // - Compute segment
173  mSeg.mP0 = lss.mP0;
174  mSeg.mP1 = lss.mP1;
175  // -> to world space
176  if(worldl)
177  {
178  mSeg.mP0 *= *worldl;
179  mSeg.mP1 *= *worldl;
180  }
181  // -> to model space
182  if(worldm)
183  {
184  // Invert model matrix
185  Matrix4x4 InvWorldM;
186  InvertPRMatrix(InvWorldM, *worldm);
187 
188  mSeg.mP0 *= InvWorldM;
189  mSeg.mP1 *= InvWorldM;
190  }
191 
192  // 3) Setup destination pointer
194 
195  // 4) Special case: 1-triangle meshes [Opcode 1.3]
197  {
198  if(!SkipPrimitiveTests())
199  {
200  // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0.
202 
203  // Perform overlap test between the unique triangle and the LSS (and set contact status if needed)
205 
206  // Return immediately regardless of status
207  return TRUE;
208  }
209  }
210 
211  // 5) Check temporal coherence :
213  {
214  // Here we use temporal coherence
215  // => check results from previous frame before performing the collision query
216  if(FirstContactEnabled())
217  {
218  // We're only interested in the first contact found => test the unique previously touched face
220  {
221  // Get index of previously touched face = the first entry in the array
222  udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0);
223 
224  // Then reset the array:
225  // - if the overlap test below is successful, the index we'll get added back anyway
226  // - if it isn't, then the array should be reset anyway for the normal query
228 
229  // Perform overlap test between the cached triangle and the LSS (and set contact status if needed)
230  LSS_PRIM(PreviouslyTouchedFace, OPC_TEMPORAL_CONTACT)
231 
232  // Return immediately if possible
233  if(GetContactStatus()) return TRUE;
234  }
235  // else no face has been touched during previous query
236  // => we'll have to perform a normal query
237  }
238  else
239  {
240  // We're interested in all contacts =>test the new real LSS N(ew) against the previous fat LSS P(revious):
241 
242  // ### rewrite this
243 
244  LSS Test(mSeg, lss.mRadius); // in model space
245  LSS Previous(cache.Previous, sqrtf(cache.Previous.mRadius));
246 
247 // if(cache.Previous.Contains(Test))
248  if(IsCacheValid(cache) && Previous.Contains(Test))
249  {
250  // - if N is included in P, return previous list
251  // => we simply leave the list (mTouchedFaces) unchanged
252 
253  // Set contact status if needed
255 
256  // In any case we don't need to do a query
257  return TRUE;
258  }
259  else
260  {
261  // - else do the query using a fat N
262 
263  // Reset cache since we'll about to perform a real query
265 
266  // Make a fat sphere so that coherence will work for subsequent frames
267  mRadius2 *= cache.FatCoeff;
268 // mRadius2 = (lss.mRadius * cache.FatCoeff)*(lss.mRadius * cache.FatCoeff);
269 
270 
271  // Update cache with query data (signature for cached faces)
272  cache.Previous.mP0 = mSeg.mP0;
273  cache.Previous.mP1 = mSeg.mP1;
274  cache.Previous.mRadius = mRadius2;
275  }
276  }
277  }
278  else
279  {
280  // Here we don't use temporal coherence => do a normal query
282  }
283 
284  return FALSE;
285 }
286 
288 
295 bool LSSCollider::Collide(LSSCache& cache, const LSS& lss, const AABBTree* tree)
297 {
298  // This is typically called for a scene tree, full of -AABBs-, not full of triangles.
299  // So we don't really have "primitives" to deal with. Hence it doesn't work with
300  // "FirstContact" + "TemporalCoherence".
302 
303  // Checkings
304  if(!tree) return false;
305 
306  // Init collision query
307  if(InitQuery(cache, lss)) return true;
308 
309  // Perform collision query
310  _Collide(tree);
311 
312  return true;
313 }
314 
316 
322 inline_ bool LSSCollider::LSSContainsBox(const Point& /*bc*/, const Point& /*be*/)
324 {
325  // Not implemented
326  return FALSE;
327 }
328 
329 #define TEST_BOX_IN_LSS(center, extents) \
330  if(LSSContainsBox(center, extents)) \
331  { \
332  /* Set contact status */ \
333  mFlags |= OPC_CONTACT; \
334  _Dump(node); \
335  return; \
336  }
337 
339 
345 {
346  // Perform LSS-AABB overlap test
347  if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
348 
349  TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents)
350 
351  if(node->IsLeaf())
352  {
353  LSS_PRIM(node->GetPrimitive(), OPC_CONTACT)
354  }
355  else
356  {
357  _Collide(node->GetPos());
358 
359  if(ContactFound()) return;
360 
361  _Collide(node->GetNeg());
362  }
363 }
364 
366 
372 {
373  // Perform LSS-AABB overlap test
374  if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
375 
376  TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents)
377 
378  if(node->IsLeaf())
379  {
380  SET_CONTACT(node->GetPrimitive(), OPC_CONTACT)
381  }
382  else
383  {
384  _CollideNoPrimitiveTest(node->GetPos());
385 
386  if(ContactFound()) return;
387 
388  _CollideNoPrimitiveTest(node->GetNeg());
389  }
390 }
391 
393 
399 {
400  // Dequantize box
401  const QuantizedAABB& Box = node->mAABB;
402  const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
403  const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
404 
405  // Perform LSS-AABB overlap test
406  if(!LSSAABBOverlap(Center, Extents)) return;
407 
408  TEST_BOX_IN_LSS(Center, Extents)
409 
410  if(node->IsLeaf())
411  {
412  LSS_PRIM(node->GetPrimitive(), OPC_CONTACT)
413  }
414  else
415  {
416  _Collide(node->GetPos());
417 
418  if(ContactFound()) return;
419 
420  _Collide(node->GetNeg());
421  }
422 }
423 
425 
431 {
432  // Dequantize box
433  const QuantizedAABB& Box = node->mAABB;
434  const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
435  const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
436 
437  // Perform LSS-AABB overlap test
438  if(!LSSAABBOverlap(Center, Extents)) return;
439 
440  TEST_BOX_IN_LSS(Center, Extents)
441 
442  if(node->IsLeaf())
443  {
444  SET_CONTACT(node->GetPrimitive(), OPC_CONTACT)
445  }
446  else
447  {
448  _CollideNoPrimitiveTest(node->GetPos());
449 
450  if(ContactFound()) return;
451 
452  _CollideNoPrimitiveTest(node->GetNeg());
453  }
454 }
455 
457 
461 void LSSCollider::_Collide(const AABBNoLeafNode* node)
463 {
464  // Perform LSS-AABB overlap test
465  if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
466 
467  TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents)
468 
469  if(node->HasPosLeaf()) { LSS_PRIM(node->GetPosPrimitive(), OPC_CONTACT) }
470  else _Collide(node->GetPos());
471 
472  if(ContactFound()) return;
473 
474  if(node->HasNegLeaf()) { LSS_PRIM(node->GetNegPrimitive(), OPC_CONTACT) }
475  else _Collide(node->GetNeg());
476 }
477 
479 
485 {
486  // Perform LSS-AABB overlap test
487  if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
488 
489  TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents)
490 
491  if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) }
492  else _CollideNoPrimitiveTest(node->GetPos());
493 
494  if(ContactFound()) return;
495 
496  if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) }
497  else _CollideNoPrimitiveTest(node->GetNeg());
498 }
499 
501 
507 {
508  // Dequantize box
509  const QuantizedAABB& Box = node->mAABB;
510  const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
511  const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
512 
513  // Perform LSS-AABB overlap test
514  if(!LSSAABBOverlap(Center, Extents)) return;
515 
516  TEST_BOX_IN_LSS(Center, Extents)
517 
518  if(node->HasPosLeaf()) { LSS_PRIM(node->GetPosPrimitive(), OPC_CONTACT) }
519  else _Collide(node->GetPos());
520 
521  if(ContactFound()) return;
522 
523  if(node->HasNegLeaf()) { LSS_PRIM(node->GetNegPrimitive(), OPC_CONTACT) }
524  else _Collide(node->GetNeg());
525 }
526 
528 
534 {
535  // Dequantize box
536  const QuantizedAABB& Box = node->mAABB;
537  const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
538  const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
539 
540  // Perform LSS-AABB overlap test
541  if(!LSSAABBOverlap(Center, Extents)) return;
542 
543  TEST_BOX_IN_LSS(Center, Extents)
544 
545  if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) }
546  else _CollideNoPrimitiveTest(node->GetPos());
547 
548  if(ContactFound()) return;
549 
550  if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) }
551  else _CollideNoPrimitiveTest(node->GetNeg());
552 }
553 
555 
559 void LSSCollider::_Collide(const AABBTreeNode* node)
561 {
562  // Perform LSS-AABB overlap test
563  Point Center, Extents;
564  node->GetAABB()->GetCenter(Center);
565  node->GetAABB()->GetExtents(Extents);
566  if(!LSSAABBOverlap(Center, Extents)) return;
567 
568  if(node->IsLeaf() || LSSContainsBox(Center, Extents))
569  {
570  mFlags |= OPC_CONTACT;
572  }
573  else
574  {
575  _Collide(node->GetPos());
576  _Collide(node->GetNeg());
577  }
578 }
579 
580 
581 
582 
583 
584 
586 
591 {
592 }
593 
595 
600 {
601 }
602 
603 bool HybridLSSCollider::Collide(LSSCache& cache, const LSS& lss, const HybridModel& model, const Matrix4x4* worldl, const Matrix4x4* worldm)
604 {
605  // We don't want primitive tests here!
607 
608  // Checkings
609  if(!Setup(&model)) return false;
610 
611  // Init collision query
612  if(InitQuery(cache, lss, worldl, worldm)) return true;
613 
614  // Special case for 1-leaf trees
616  {
617  // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles
618  udword Nb = mIMesh->GetNbTriangles();
619 
620  // Loop through all triangles
621  for(udword i=0;i<Nb;i++)
622  {
624  }
625  return true;
626  }
627 
628  // Override destination array since we're only going to get leaf boxes here
629  mTouchedBoxes.Reset();
630  mTouchedPrimitives = &mTouchedBoxes;
631 
632  // Now, do the actual query against leaf boxes
633  if(!model.HasLeafNodes())
634  {
635  if(model.IsQuantized())
636  {
637  const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
638 
639  // Setup dequantization coeffs
640  mCenterCoeff = Tree->mCenterCoeff;
642 
643  // Perform collision query - we don't want primitive tests here!
644  _CollideNoPrimitiveTest(Tree->GetNodes());
645  }
646  else
647  {
648  const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
649 
650  // Perform collision query - we don't want primitive tests here!
651  _CollideNoPrimitiveTest(Tree->GetNodes());
652  }
653  }
654  else
655  {
656  if(model.IsQuantized())
657  {
658  const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
659 
660  // Setup dequantization coeffs
661  mCenterCoeff = Tree->mCenterCoeff;
663 
664  // Perform collision query - we don't want primitive tests here!
665  _CollideNoPrimitiveTest(Tree->GetNodes());
666  }
667  else
668  {
669  const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
670 
671  // Perform collision query - we don't want primitive tests here!
672  _CollideNoPrimitiveTest(Tree->GetNodes());
673  }
674  }
675 
676  // We only have a list of boxes so far
677  if(GetContactStatus())
678  {
679  // Reset contact status, since it currently only reflects collisions with leaf boxes
681 
682  // Change dest container so that we can use built-in overlap tests and get collided primitives
683  cache.TouchedPrimitives.Reset();
685 
686  // Read touched leaf boxes
687  udword Nb = mTouchedBoxes.GetNbEntries();
688  const udword* Touched = mTouchedBoxes.GetEntries();
689 
690  const LeafTriangles* LT = model.GetLeafTriangles();
691  const udword* Indices = model.GetIndices();
692 
693  // Loop through touched leaves
694  while(Nb--)
695  {
696  const LeafTriangles& CurrentLeaf = LT[*Touched++];
697 
698  // Each leaf box has a set of triangles
699  udword NbTris = CurrentLeaf.GetNbTriangles();
700  if(Indices)
701  {
702  const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()];
703 
704  // Loop through triangles and test each of them
705  while(NbTris--)
706  {
707  udword TriangleIndex = *T++;
708  LSS_PRIM(TriangleIndex, OPC_CONTACT)
709  }
710  }
711  else
712  {
713  udword BaseIndex = CurrentLeaf.GetTriangleIndex();
714 
715  // Loop through triangles and test each of them
716  while(NbTris--)
717  {
718  udword TriangleIndex = BaseIndex++;
719  LSS_PRIM(TriangleIndex, OPC_CONTACT)
720  }
721  }
722  }
723  }
724 
725  return true;
726 }
727