1 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3 * OPCODE - Optimized Collision Detection
4 * Copyright (C) 2001 Pierre Terdiman
5 * Homepage: http://www.codercorner.com/Opcode.htm
7 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
9 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
11 * Contains code for a sphere collider.
12 * \file OPC_SphereCollider.cpp
13 * \author Pierre Terdiman
16 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
18 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
20 * Contains a sphere-vs-tree collider.
21 * This class performs a collision test between a sphere and an AABB tree. You can use this to do a standard player vs world collision,
22 * in a Nettle/Telemachos way. It doesn't suffer from all reported bugs in those two classic codes - the "new" one by Paul Nettle is a
23 * debuggued version I think. Collision response can be driven by reported collision data - it works extremely well for me. In sake of
24 * efficiency, all meshes (that is, all AABB trees) should of course also be kept in an extra hierarchical structure (octree, whatever).
26 * \class SphereCollider
27 * \author Pierre Terdiman
31 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
33 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
37 using namespace Opcode
;
39 #include "OPC_SphereAABBOverlap.h"
40 #include "OPC_SphereTriOverlap.h"
42 #define SET_CONTACT(prim_index, flag) \
43 /* Set contact status */ \
45 mTouchedPrimitives->Add(udword(prim_index));
47 //! Sphere-triangle overlap test
48 #define SPHERE_PRIM(prim_index, flag) \
49 /* Request vertices from the app */ \
50 VertexPointers VP; ConversionArea VC; mIMesh->GetTriangle(VP, prim_index, VC); \
52 /* Perform sphere-tri overlap test */ \
53 if(SphereTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \
55 SET_CONTACT(prim_index, flag) \
58 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
62 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
63 SphereCollider::SphereCollider()
69 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
73 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
74 SphereCollider::~SphereCollider()
78 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
80 * Generic collision query for generic OPCODE models. After the call, access the results:
81 * - with GetContactStatus()
82 * - with GetNbTouchedPrimitives()
83 * - with GetTouchedPrimitives()
85 * \param cache [in/out] a sphere cache
86 * \param sphere [in] collision sphere in local space
87 * \param model [in] Opcode model to collide with
88 * \param worlds [in] sphere's world matrix, or null
89 * \param worldm [in] model's world matrix, or null
90 * \return true if success
91 * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
93 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
94 bool SphereCollider::Collide(SphereCache
& cache
, const Sphere
& sphere
, const Model
& model
, const Matrix4x4
* worlds
, const Matrix4x4
* worldm
)
97 if(!Setup(&model
)) return false;
99 // Init collision query
100 if(InitQuery(cache
, sphere
, worlds
, worldm
)) return true;
102 // Special case for 1-leaf trees
103 if(mCurrentModel
&& mCurrentModel
->HasSingleNode())
105 // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles
106 udword Nb
= mIMesh
->GetNbTriangles();
107 // Loop through all triangles
108 for(udword i
=0;i
<Nb
;i
++)
110 SPHERE_PRIM(i
, OPC_CONTACT
)
115 if(!model
.HasLeafNodes())
117 if(model
.IsQuantized())
119 const AABBQuantizedNoLeafTree
* Tree
= static_cast<const AABBQuantizedNoLeafTree
*>(model
.GetTree());
121 // Setup dequantization coeffs
122 mCenterCoeff
= Tree
->mCenterCoeff
;
123 mExtentsCoeff
= Tree
->mExtentsCoeff
;
125 // Perform collision query
126 if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree
->GetNodes());
127 else _Collide(Tree
->GetNodes());
131 const AABBNoLeafTree
* Tree
= static_cast<const AABBNoLeafTree
*>(model
.GetTree());
133 // Perform collision query
134 if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree
->GetNodes());
135 else _Collide(Tree
->GetNodes());
140 if(model
.IsQuantized())
142 const AABBQuantizedTree
* Tree
= static_cast<const AABBQuantizedTree
*>(model
.GetTree());
144 // Setup dequantization coeffs
145 mCenterCoeff
= Tree
->mCenterCoeff
;
146 mExtentsCoeff
= Tree
->mExtentsCoeff
;
148 // Perform collision query
149 if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree
->GetNodes());
150 else _Collide(Tree
->GetNodes());
154 const AABBCollisionTree
* Tree
= static_cast<const AABBCollisionTree
*>(model
.GetTree());
156 // Perform collision query
157 if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree
->GetNodes());
158 else _Collide(Tree
->GetNodes());
164 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
166 * Initializes a collision query :
167 * - reset stats & contact status
169 * - check temporal coherence
171 * \param cache [in/out] a sphere cache
172 * \param sphere [in] sphere in local space
173 * \param worlds [in] sphere's world matrix, or null
174 * \param worldm [in] model's world matrix, or null
175 * \return TRUE if we can return immediately
176 * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
178 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
179 BOOL
SphereCollider::InitQuery(SphereCache
& cache
, const Sphere
& sphere
, const Matrix4x4
* worlds
, const Matrix4x4
* worldm
)
181 // 1) Call the base method
182 VolumeCollider::InitQuery();
184 // 2) Compute sphere in model space:
186 mRadius2
= sphere
.mRadius
* sphere
.mRadius
;
187 // - Compute center position
188 mCenter
= sphere
.mCenter
;
190 if(worlds
) mCenter
*= *worlds
;
194 // Invert model matrix
196 InvertPRMatrix(InvWorldM
, *worldm
);
198 mCenter
*= InvWorldM
;
201 // 3) Setup destination pointer
202 mTouchedPrimitives
= &cache
.TouchedPrimitives
;
204 // 4) Special case: 1-triangle meshes [Opcode 1.3]
205 if(mCurrentModel
&& mCurrentModel
->HasSingleNode())
207 if(!SkipPrimitiveTests())
209 // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0.
210 mTouchedPrimitives
->Reset();
212 // Perform overlap test between the unique triangle and the sphere (and set contact status if needed)
213 SPHERE_PRIM(udword(0), OPC_CONTACT
)
215 // Return immediately regardless of status
220 // 5) Check temporal coherence :
221 if(TemporalCoherenceEnabled())
223 // Here we use temporal coherence
224 // => check results from previous frame before performing the collision query
225 if(FirstContactEnabled())
227 // We're only interested in the first contact found => test the unique previously touched face
228 if(mTouchedPrimitives
->GetNbEntries())
230 // Get index of previously touched face = the first entry in the array
231 udword PreviouslyTouchedFace
= mTouchedPrimitives
->GetEntry(0);
233 // Then reset the array:
234 // - if the overlap test below is successful, the index we'll get added back anyway
235 // - if it isn't, then the array should be reset anyway for the normal query
236 mTouchedPrimitives
->Reset();
238 // Perform overlap test between the cached triangle and the sphere (and set contact status if needed)
239 SPHERE_PRIM(PreviouslyTouchedFace
, OPC_TEMPORAL_CONTACT
)
241 // Return immediately if possible
242 if(GetContactStatus()) return TRUE
;
244 // else no face has been touched during previous query
245 // => we'll have to perform a normal query
249 // We're interested in all contacts =>test the new real sphere N(ew) against the previous fat sphere P(revious):
250 float r
= sqrtf(cache
.FatRadius2
) - sphere
.mRadius
;
251 if(IsCacheValid(cache
) && cache
.Center
.SquareDistance(mCenter
) < r
*r
)
253 // - if N is included in P, return previous list
254 // => we simply leave the list (mTouchedFaces) unchanged
256 // Set contact status if needed
257 if(mTouchedPrimitives
->GetNbEntries()) mFlags
|= OPC_TEMPORAL_CONTACT
;
259 // In any case we don't need to do a query
264 // - else do the query using a fat N
266 // Reset cache since we'll about to perform a real query
267 mTouchedPrimitives
->Reset();
269 // Make a fat sphere so that coherence will work for subsequent frames
270 mRadius2
*= cache
.FatCoeff
;
271 // mRadius2 = (sphere.mRadius * cache.FatCoeff)*(sphere.mRadius * cache.FatCoeff);
273 // Update cache with query data (signature for cached faces)
274 cache
.Center
= mCenter
;
275 cache
.FatRadius2
= mRadius2
;
281 // Here we don't use temporal coherence => do a normal query
282 mTouchedPrimitives
->Reset();
288 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
290 * Collision query for vanilla AABB trees.
291 * \param cache [in/out] a sphere cache
292 * \param sphere [in] collision sphere in world space
293 * \param tree [in] AABB tree
294 * \return true if success
296 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
297 bool SphereCollider::Collide(SphereCache
& cache
, const Sphere
& sphere
, const AABBTree
* tree
)
299 // This is typically called for a scene tree, full of -AABBs-, not full of triangles.
300 // So we don't really have "primitives" to deal with. Hence it doesn't work with
301 // "FirstContact" + "TemporalCoherence".
302 ASSERT( !(FirstContactEnabled() && TemporalCoherenceEnabled()) );
305 if(!tree
) return false;
307 // Init collision query
308 if(InitQuery(cache
, sphere
)) return true;
310 // Perform collision query
316 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
318 * Checks the sphere completely contains the box. In which case we can end the query sooner.
319 * \param bc [in] box center
320 * \param be [in] box extents
321 * \return true if the sphere contains the whole box
323 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
324 inline_ BOOL
SphereCollider::SphereContainsBox(const Point
& bc
, const Point
& be
)
326 // I assume if all 8 box vertices are inside the sphere, so does the whole box.
327 // Sounds ok but maybe there's a better way?
329 p
.x
=bc
.x
+be
.x
; p
.y
=bc
.y
+be
.y
; p
.z
=bc
.z
+be
.z
; if(mCenter
.SquareDistance(p
)>=mRadius2
) return FALSE
;
330 p
.x
=bc
.x
-be
.x
; if(mCenter
.SquareDistance(p
)>=mRadius2
) return FALSE
;
331 p
.x
=bc
.x
+be
.x
; p
.y
=bc
.y
-be
.y
; if(mCenter
.SquareDistance(p
)>=mRadius2
) return FALSE
;
332 p
.x
=bc
.x
-be
.x
; if(mCenter
.SquareDistance(p
)>=mRadius2
) return FALSE
;
333 p
.x
=bc
.x
+be
.x
; p
.y
=bc
.y
+be
.y
; p
.z
=bc
.z
-be
.z
; if(mCenter
.SquareDistance(p
)>=mRadius2
) return FALSE
;
334 p
.x
=bc
.x
-be
.x
; if(mCenter
.SquareDistance(p
)>=mRadius2
) return FALSE
;
335 p
.x
=bc
.x
+be
.x
; p
.y
=bc
.y
-be
.y
; if(mCenter
.SquareDistance(p
)>=mRadius2
) return FALSE
;
336 p
.x
=bc
.x
-be
.x
; if(mCenter
.SquareDistance(p
)>=mRadius2
) return FALSE
;
341 #define TEST_BOX_IN_SPHERE(center, extents) \
342 if(SphereContainsBox(center, extents)) \
344 /* Set contact status */ \
345 mFlags |= OPC_CONTACT; \
350 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
352 * Recursive collision query for normal AABB trees.
353 * \param node [in] current collision node
355 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
356 void SphereCollider::_Collide(const AABBCollisionNode
* node
)
358 // Perform Sphere-AABB overlap test
359 if(!SphereAABBOverlap(node
->mAABB
.mCenter
, node
->mAABB
.mExtents
)) return;
361 TEST_BOX_IN_SPHERE(node
->mAABB
.mCenter
, node
->mAABB
.mExtents
)
365 SPHERE_PRIM(node
->GetPrimitive(), OPC_CONTACT
)
369 _Collide(node
->GetPos());
371 if(ContactFound()) return;
373 _Collide(node
->GetNeg());
377 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
379 * Recursive collision query for normal AABB trees, without primitive tests.
380 * \param node [in] current collision node
382 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
383 void SphereCollider::_CollideNoPrimitiveTest(const AABBCollisionNode
* node
)
385 // Perform Sphere-AABB overlap test
386 if(!SphereAABBOverlap(node
->mAABB
.mCenter
, node
->mAABB
.mExtents
)) return;
388 TEST_BOX_IN_SPHERE(node
->mAABB
.mCenter
, node
->mAABB
.mExtents
)
392 SET_CONTACT(node
->GetPrimitive(), OPC_CONTACT
)
396 _CollideNoPrimitiveTest(node
->GetPos());
398 if(ContactFound()) return;
400 _CollideNoPrimitiveTest(node
->GetNeg());
404 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
406 * Recursive collision query for quantized AABB trees.
407 * \param node [in] current collision node
409 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
410 void SphereCollider::_Collide(const AABBQuantizedNode
* node
)
413 const QuantizedAABB
& Box
= node
->mAABB
;
414 const Point
Center(float(Box
.mCenter
[0]) * mCenterCoeff
.x
, float(Box
.mCenter
[1]) * mCenterCoeff
.y
, float(Box
.mCenter
[2]) * mCenterCoeff
.z
);
415 const Point
Extents(float(Box
.mExtents
[0]) * mExtentsCoeff
.x
, float(Box
.mExtents
[1]) * mExtentsCoeff
.y
, float(Box
.mExtents
[2]) * mExtentsCoeff
.z
);
417 // Perform Sphere-AABB overlap test
418 if(!SphereAABBOverlap(Center
, Extents
)) return;
420 TEST_BOX_IN_SPHERE(Center
, Extents
)
424 SPHERE_PRIM(node
->GetPrimitive(), OPC_CONTACT
)
428 _Collide(node
->GetPos());
430 if(ContactFound()) return;
432 _Collide(node
->GetNeg());
436 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
438 * Recursive collision query for quantized AABB trees, without primitive tests.
439 * \param node [in] current collision node
441 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
442 void SphereCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode
* node
)
445 const QuantizedAABB
& Box
= node
->mAABB
;
446 const Point
Center(float(Box
.mCenter
[0]) * mCenterCoeff
.x
, float(Box
.mCenter
[1]) * mCenterCoeff
.y
, float(Box
.mCenter
[2]) * mCenterCoeff
.z
);
447 const Point
Extents(float(Box
.mExtents
[0]) * mExtentsCoeff
.x
, float(Box
.mExtents
[1]) * mExtentsCoeff
.y
, float(Box
.mExtents
[2]) * mExtentsCoeff
.z
);
449 // Perform Sphere-AABB overlap test
450 if(!SphereAABBOverlap(Center
, Extents
)) return;
452 TEST_BOX_IN_SPHERE(Center
, Extents
)
456 SET_CONTACT(node
->GetPrimitive(), OPC_CONTACT
)
460 _CollideNoPrimitiveTest(node
->GetPos());
462 if(ContactFound()) return;
464 _CollideNoPrimitiveTest(node
->GetNeg());
468 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
470 * Recursive collision query for no-leaf AABB trees.
471 * \param node [in] current collision node
473 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
474 void SphereCollider::_Collide(const AABBNoLeafNode
* node
)
476 // Perform Sphere-AABB overlap test
477 if(!SphereAABBOverlap(node
->mAABB
.mCenter
, node
->mAABB
.mExtents
)) return;
479 TEST_BOX_IN_SPHERE(node
->mAABB
.mCenter
, node
->mAABB
.mExtents
)
481 if(node
->HasPosLeaf()) { SPHERE_PRIM(node
->GetPosPrimitive(), OPC_CONTACT
) }
482 else _Collide(node
->GetPos());
484 if(ContactFound()) return;
486 if(node
->HasNegLeaf()) { SPHERE_PRIM(node
->GetNegPrimitive(), OPC_CONTACT
) }
487 else _Collide(node
->GetNeg());
490 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
492 * Recursive collision query for no-leaf AABB trees, without primitive tests.
493 * \param node [in] current collision node
495 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
496 void SphereCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode
* node
)
498 // Perform Sphere-AABB overlap test
499 if(!SphereAABBOverlap(node
->mAABB
.mCenter
, node
->mAABB
.mExtents
)) return;
501 TEST_BOX_IN_SPHERE(node
->mAABB
.mCenter
, node
->mAABB
.mExtents
)
503 if(node
->HasPosLeaf()) { SET_CONTACT(node
->GetPosPrimitive(), OPC_CONTACT
) }
504 else _CollideNoPrimitiveTest(node
->GetPos());
506 if(ContactFound()) return;
508 if(node
->HasNegLeaf()) { SET_CONTACT(node
->GetNegPrimitive(), OPC_CONTACT
) }
509 else _CollideNoPrimitiveTest(node
->GetNeg());
512 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
514 * Recursive collision query for quantized no-leaf AABB trees.
515 * \param node [in] current collision node
517 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
518 void SphereCollider::_Collide(const AABBQuantizedNoLeafNode
* node
)
521 const QuantizedAABB
& Box
= node
->mAABB
;
522 const Point
Center(float(Box
.mCenter
[0]) * mCenterCoeff
.x
, float(Box
.mCenter
[1]) * mCenterCoeff
.y
, float(Box
.mCenter
[2]) * mCenterCoeff
.z
);
523 const Point
Extents(float(Box
.mExtents
[0]) * mExtentsCoeff
.x
, float(Box
.mExtents
[1]) * mExtentsCoeff
.y
, float(Box
.mExtents
[2]) * mExtentsCoeff
.z
);
525 // Perform Sphere-AABB overlap test
526 if(!SphereAABBOverlap(Center
, Extents
)) return;
528 TEST_BOX_IN_SPHERE(Center
, Extents
)
530 if(node
->HasPosLeaf()) { SPHERE_PRIM(node
->GetPosPrimitive(), OPC_CONTACT
) }
531 else _Collide(node
->GetPos());
533 if(ContactFound()) return;
535 if(node
->HasNegLeaf()) { SPHERE_PRIM(node
->GetNegPrimitive(), OPC_CONTACT
) }
536 else _Collide(node
->GetNeg());
539 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
541 * Recursive collision query for quantized no-leaf AABB trees, without primitive tests.
542 * \param node [in] current collision node
544 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
545 void SphereCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode
* node
)
548 const QuantizedAABB
& Box
= node
->mAABB
;
549 const Point
Center(float(Box
.mCenter
[0]) * mCenterCoeff
.x
, float(Box
.mCenter
[1]) * mCenterCoeff
.y
, float(Box
.mCenter
[2]) * mCenterCoeff
.z
);
550 const Point
Extents(float(Box
.mExtents
[0]) * mExtentsCoeff
.x
, float(Box
.mExtents
[1]) * mExtentsCoeff
.y
, float(Box
.mExtents
[2]) * mExtentsCoeff
.z
);
552 // Perform Sphere-AABB overlap test
553 if(!SphereAABBOverlap(Center
, Extents
)) return;
555 TEST_BOX_IN_SPHERE(Center
, Extents
)
557 if(node
->HasPosLeaf()) { SET_CONTACT(node
->GetPosPrimitive(), OPC_CONTACT
) }
558 else _CollideNoPrimitiveTest(node
->GetPos());
560 if(ContactFound()) return;
562 if(node
->HasNegLeaf()) { SET_CONTACT(node
->GetNegPrimitive(), OPC_CONTACT
) }
563 else _CollideNoPrimitiveTest(node
->GetNeg());
566 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
568 * Recursive collision query for vanilla AABB trees.
569 * \param node [in] current collision node
571 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
572 void SphereCollider::_Collide(const AABBTreeNode
* node
)
574 // Perform Sphere-AABB overlap test
575 Point Center
, Extents
;
576 node
->GetAABB()->GetCenter(Center
);
577 node
->GetAABB()->GetExtents(Extents
);
578 if(!SphereAABBOverlap(Center
, Extents
)) return;
580 if(node
->IsLeaf() || SphereContainsBox(Center
, Extents
))
582 mFlags
|= OPC_CONTACT
;
583 mTouchedPrimitives
->Add(node
->GetPrimitives(), node
->GetNbPrimitives());
587 _Collide(node
->GetPos());
588 _Collide(node
->GetNeg());
598 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
602 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
603 HybridSphereCollider::HybridSphereCollider()
607 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
611 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
612 HybridSphereCollider::~HybridSphereCollider()
616 bool HybridSphereCollider::Collide(SphereCache
& cache
, const Sphere
& sphere
, const HybridModel
& model
, const Matrix4x4
* worlds
, const Matrix4x4
* worldm
)
618 // We don't want primitive tests here!
619 mFlags
|= OPC_NO_PRIMITIVE_TESTS
;
622 if(!Setup(&model
)) return false;
624 // Init collision query
625 if(InitQuery(cache
, sphere
, worlds
, worldm
)) return true;
627 // Special case for 1-leaf trees
628 if(mCurrentModel
&& mCurrentModel
->HasSingleNode())
630 // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles
631 udword Nb
= mIMesh
->GetNbTriangles();
633 // Loop through all triangles
634 for(udword i
=0;i
<Nb
;i
++)
636 SPHERE_PRIM(i
, OPC_CONTACT
)
641 // Override destination array since we're only going to get leaf boxes here
642 mTouchedBoxes
.Reset();
643 mTouchedPrimitives
= &mTouchedBoxes
;
645 // Now, do the actual query against leaf boxes
646 if(!model
.HasLeafNodes())
648 if(model
.IsQuantized())
650 const AABBQuantizedNoLeafTree
* Tree
= static_cast<const AABBQuantizedNoLeafTree
*>(model
.GetTree());
652 // Setup dequantization coeffs
653 mCenterCoeff
= Tree
->mCenterCoeff
;
654 mExtentsCoeff
= Tree
->mExtentsCoeff
;
656 // Perform collision query - we don't want primitive tests here!
657 _CollideNoPrimitiveTest(Tree
->GetNodes());
661 const AABBNoLeafTree
* Tree
= static_cast<const AABBNoLeafTree
*>(model
.GetTree());
663 // Perform collision query - we don't want primitive tests here!
664 _CollideNoPrimitiveTest(Tree
->GetNodes());
669 if(model
.IsQuantized())
671 const AABBQuantizedTree
* Tree
= static_cast<const AABBQuantizedTree
*>(model
.GetTree());
673 // Setup dequantization coeffs
674 mCenterCoeff
= Tree
->mCenterCoeff
;
675 mExtentsCoeff
= Tree
->mExtentsCoeff
;
677 // Perform collision query - we don't want primitive tests here!
678 _CollideNoPrimitiveTest(Tree
->GetNodes());
682 const AABBCollisionTree
* Tree
= static_cast<const AABBCollisionTree
*>(model
.GetTree());
684 // Perform collision query - we don't want primitive tests here!
685 _CollideNoPrimitiveTest(Tree
->GetNodes());
689 // We only have a list of boxes so far
690 if(GetContactStatus())
692 // Reset contact status, since it currently only reflects collisions with leaf boxes
693 Collider::InitQuery();
695 // Change dest container so that we can use built-in overlap tests and get collided primitives
696 cache
.TouchedPrimitives
.Reset();
697 mTouchedPrimitives
= &cache
.TouchedPrimitives
;
699 // Read touched leaf boxes
700 udword Nb
= mTouchedBoxes
.GetNbEntries();
701 const udword
* Touched
= mTouchedBoxes
.GetEntries();
703 const LeafTriangles
* LT
= model
.GetLeafTriangles();
704 const udword
* Indices
= model
.GetIndices();
706 // Loop through touched leaves
709 const LeafTriangles
& CurrentLeaf
= LT
[*Touched
++];
711 // Each leaf box has a set of triangles
712 udword NbTris
= CurrentLeaf
.GetNbTriangles();
715 const udword
* T
= &Indices
[CurrentLeaf
.GetTriangleIndex()];
717 // Loop through triangles and test each of them
720 udword TriangleIndex
= *T
++;
721 SPHERE_PRIM(TriangleIndex
, OPC_CONTACT
)
726 udword BaseIndex
= CurrentLeaf
.GetTriangleIndex();
728 // Loop through triangles and test each of them
731 udword TriangleIndex
= BaseIndex
++;
732 SPHERE_PRIM(TriangleIndex
, OPC_CONTACT
)