123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942 |
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /*
- * OPCODE - Optimized Collision Detection
- * Copyright (C) 2001 Pierre Terdiman
- * Homepage: http://www.codercorner.com/Opcode.htm
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Contains code for a tree collider.
- * \file OPC_TreeCollider.cpp
- * \author Pierre Terdiman
- * \date March, 20, 2001
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Contains an AABB tree collider.
- * This class performs a collision test between two AABB trees.
- *
- * \class AABBTreeCollider
- * \author Pierre Terdiman
- * \version 1.3
- * \date March, 20, 2001
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- #include "Opcode.h"
- using namespace Opcode;
- #include "OPC_BoxBoxOverlap.h"
- #include "OPC_TriBoxOverlap.h"
- #include "OPC_TriTriOverlap.h"
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Constructor.
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- AABBTreeCollider::AABBTreeCollider() :
- mNbBVBVTests (0),
- mNbPrimPrimTests (0),
- mNbBVPrimTests (0),
- mFullBoxBoxTest (true),
- mFullPrimBoxTest (true),
- mIMesh0 (null),
- mIMesh1 (null)
- {
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Destructor.
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- AABBTreeCollider::~AABBTreeCollider()
- {
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Validates current settings. You should call this method after all the settings and callbacks have been defined.
- * \return null if everything is ok, else a string describing the problem
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- const char* AABBTreeCollider::ValidateSettings()
- {
- if(TemporalCoherenceEnabled() && !FirstContactEnabled()) return "Temporal coherence only works with ""First contact"" mode!";
- return null;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Generic collision query for generic OPCODE models. After the call, access the results with:
- * - GetContactStatus()
- * - GetNbPairs()
- * - GetPairs()
- *
- * \param cache [in] collision cache for model pointers and a colliding pair of primitives
- * \param world0 [in] world matrix for first object
- * \param world1 [in] world matrix for second object
- * \return true if success
- * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- bool AABBTreeCollider::Collide(BVTCache& cache, const Matrix4x4* world0, const Matrix4x4* world1)
- {
- // Checkings
- if(!cache.Model0 || !cache.Model1) return false;
- if(cache.Model0->HasLeafNodes()!=cache.Model1->HasLeafNodes()) return false;
- if(cache.Model0->IsQuantized()!=cache.Model1->IsQuantized()) return false;
- /*
-
- Rules:
- - perform hull test
- - when hulls collide, disable hull test
- - if meshes overlap, reset countdown
- - if countdown reaches 0, enable hull test
- */
- #ifdef __MESHMERIZER_H__
- // Handle hulls
- if(cache.HullTest)
- {
- if(cache.Model0->GetHull() && cache.Model1->GetHull())
- {
- struct Local
- {
- static Point* SVCallback(const Point& sv, udword& previndex, udword user_data)
- {
- CollisionHull* Hull = (CollisionHull*)user_data;
- previndex = Hull->ComputeSupportingVertex(sv, previndex);
- return (Point*)&Hull->GetVerts()[previndex];
- }
- };
- bool Collide;
- if(0)
- {
- static GJKEngine GJK;
- static bool GJKInitDone=false;
- if(!GJKInitDone)
- {
- GJK.Enable(GJK_BACKUP_PROCEDURE);
- GJK.Enable(GJK_DEGENERATE);
- GJK.Enable(GJK_HILLCLIMBING);
- GJKInitDone = true;
- }
- GJK.SetCallbackObj0(Local::SVCallback);
- GJK.SetCallbackObj1(Local::SVCallback);
- GJK.SetUserData0(udword(cache.Model0->GetHull()));
- GJK.SetUserData1(udword(cache.Model1->GetHull()));
- Collide = GJK.Collide(*world0, *world1, &cache.SepVector);
- }
- else
- {
- static SVEngine SVE;
- SVE.SetCallbackObj0(Local::SVCallback);
- SVE.SetCallbackObj1(Local::SVCallback);
- SVE.SetUserData0(udword(cache.Model0->GetHull()));
- SVE.SetUserData1(udword(cache.Model1->GetHull()));
- Collide = SVE.Collide(*world0, *world1, &cache.SepVector);
- }
- if(!Collide)
- {
- // Reset stats & contact status
- mFlags &= ~OPC_CONTACT;
- mNbBVBVTests = 0;
- mNbPrimPrimTests = 0;
- mNbBVPrimTests = 0;
- mPairs.Reset();
- return true;
- }
- }
- }
- // Here, hulls collide
- cache.HullTest = false;
- #endif // __MESHMERIZER_H__
- // Checkings
- if(!Setup(cache.Model0->GetMeshInterface(), cache.Model1->GetMeshInterface())) return false;
- // Simple double-dispatch
- bool Status;
- if(!cache.Model0->HasLeafNodes())
- {
- if(cache.Model0->IsQuantized())
- {
- const AABBQuantizedNoLeafTree* T0 = (const AABBQuantizedNoLeafTree*)cache.Model0->GetTree();
- const AABBQuantizedNoLeafTree* T1 = (const AABBQuantizedNoLeafTree*)cache.Model1->GetTree();
- Status = Collide(T0, T1, world0, world1, &cache);
- }
- else
- {
- const AABBNoLeafTree* T0 = (const AABBNoLeafTree*)cache.Model0->GetTree();
- const AABBNoLeafTree* T1 = (const AABBNoLeafTree*)cache.Model1->GetTree();
- Status = Collide(T0, T1, world0, world1, &cache);
- }
- }
- else
- {
- if(cache.Model0->IsQuantized())
- {
- const AABBQuantizedTree* T0 = (const AABBQuantizedTree*)cache.Model0->GetTree();
- const AABBQuantizedTree* T1 = (const AABBQuantizedTree*)cache.Model1->GetTree();
- Status = Collide(T0, T1, world0, world1, &cache);
- }
- else
- {
- const AABBCollisionTree* T0 = (const AABBCollisionTree*)cache.Model0->GetTree();
- const AABBCollisionTree* T1 = (const AABBCollisionTree*)cache.Model1->GetTree();
- Status = Collide(T0, T1, world0, world1, &cache);
- }
- }
- #ifdef __MESHMERIZER_H__
- if(Status)
- {
- // Reset counter as long as overlap occurs
- if(GetContactStatus()) cache.ResetCountDown();
- // Enable hull test again when counter reaches zero
- cache.CountDown--;
- if(!cache.CountDown)
- {
- cache.ResetCountDown();
- cache.HullTest = true;
- }
- }
- #endif
- return Status;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Initializes a collision query :
- * - reset stats & contact status
- * - setup matrices
- *
- * \param world0 [in] world matrix for first object
- * \param world1 [in] world matrix for second object
- * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void AABBTreeCollider::InitQuery(const Matrix4x4* world0, const Matrix4x4* world1)
- {
- // Reset stats & contact status
- Collider::InitQuery();
- mNbBVBVTests = 0;
- mNbPrimPrimTests = 0;
- mNbBVPrimTests = 0;
- mPairs.Reset();
- // Setup matrices
- Matrix4x4 InvWorld0, InvWorld1;
- if(world0) InvertPRMatrix(InvWorld0, *world0);
- else InvWorld0.Identity();
- if(world1) InvertPRMatrix(InvWorld1, *world1);
- else InvWorld1.Identity();
- Matrix4x4 World0to1 = world0 ? (*world0 * InvWorld1) : InvWorld1;
- Matrix4x4 World1to0 = world1 ? (*world1 * InvWorld0) : InvWorld0;
- mR0to1 = World0to1; World0to1.GetTrans(mT0to1);
- mR1to0 = World1to0; World1to0.GetTrans(mT1to0);
- // Precompute absolute 1-to-0 rotation matrix
- for(udword i=0;i<3;i++)
- {
- for(udword j=0;j<3;j++)
- {
- // Epsilon value prevents floating-point inaccuracies (strategy borrowed from RAPID)
- mAR.m[i][j] = 1e-6f + fabsf(mR1to0.m[i][j]);
- }
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Takes advantage of temporal coherence.
- * \param cache [in] cache for a pair of previously colliding primitives
- * \return true if we can return immediately
- * \warning only works for "First Contact" mode
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- bool AABBTreeCollider::CheckTemporalCoherence(Pair* cache)
- {
- // Checkings
- if(!cache) return false;
- // Test previously colliding primitives first
- if(TemporalCoherenceEnabled() && FirstContactEnabled())
- {
- PrimTest(cache->id0, cache->id1);
- if(GetContactStatus()) return true;
- }
- return false;
- }
- #define UPDATE_CACHE \
- if(cache && GetContactStatus()) \
- { \
- cache->id0 = mPairs.GetEntry(0); \
- cache->id1 = mPairs.GetEntry(1); \
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Collision query for normal AABB trees.
- * \param tree0 [in] AABB tree from first object
- * \param tree1 [in] AABB tree from second object
- * \param world0 [in] world matrix for first object
- * \param world1 [in] world matrix for second object
- * \param cache [in/out] cache for a pair of previously colliding primitives
- * \return true if success
- * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- bool AABBTreeCollider::Collide(const AABBCollisionTree* tree0, const AABBCollisionTree* tree1, const Matrix4x4* world0, const Matrix4x4* world1, Pair* cache)
- {
- // Init collision query
- InitQuery(world0, world1);
- // Check previous state
- if(CheckTemporalCoherence(cache)) return true;
- // Perform collision query
- _Collide(tree0->GetNodes(), tree1->GetNodes());
- UPDATE_CACHE
- return true;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Collision query for no-leaf AABB trees.
- * \param tree0 [in] AABB tree from first object
- * \param tree1 [in] AABB tree from second object
- * \param world0 [in] world matrix for first object
- * \param world1 [in] world matrix for second object
- * \param cache [in/out] cache for a pair of previously colliding primitives
- * \return true if success
- * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- bool AABBTreeCollider::Collide(const AABBNoLeafTree* tree0, const AABBNoLeafTree* tree1, const Matrix4x4* world0, const Matrix4x4* world1, Pair* cache)
- {
- // Init collision query
- InitQuery(world0, world1);
- // Check previous state
- if(CheckTemporalCoherence(cache)) return true;
- // Perform collision query
- _Collide(tree0->GetNodes(), tree1->GetNodes());
- UPDATE_CACHE
- return true;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Collision query for quantized AABB trees.
- * \param tree0 [in] AABB tree from first object
- * \param tree1 [in] AABB tree from second object
- * \param world0 [in] world matrix for first object
- * \param world1 [in] world matrix for second object
- * \param cache [in/out] cache for a pair of previously colliding primitives
- * \return true if success
- * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- bool AABBTreeCollider::Collide(const AABBQuantizedTree* tree0, const AABBQuantizedTree* tree1, const Matrix4x4* world0, const Matrix4x4* world1, Pair* cache)
- {
- // Init collision query
- InitQuery(world0, world1);
- // Check previous state
- if(CheckTemporalCoherence(cache)) return true;
- // Setup dequantization coeffs
- mCenterCoeff0 = tree0->mCenterCoeff;
- mExtentsCoeff0 = tree0->mExtentsCoeff;
- mCenterCoeff1 = tree1->mCenterCoeff;
- mExtentsCoeff1 = tree1->mExtentsCoeff;
- // Dequantize box A
- const AABBQuantizedNode* N0 = tree0->GetNodes();
- const Point a(float(N0->mAABB.mExtents[0]) * mExtentsCoeff0.x, float(N0->mAABB.mExtents[1]) * mExtentsCoeff0.y, float(N0->mAABB.mExtents[2]) * mExtentsCoeff0.z);
- const Point Pa(float(N0->mAABB.mCenter[0]) * mCenterCoeff0.x, float(N0->mAABB.mCenter[1]) * mCenterCoeff0.y, float(N0->mAABB.mCenter[2]) * mCenterCoeff0.z);
- // Dequantize box B
- const AABBQuantizedNode* N1 = tree1->GetNodes();
- const Point b(float(N1->mAABB.mExtents[0]) * mExtentsCoeff1.x, float(N1->mAABB.mExtents[1]) * mExtentsCoeff1.y, float(N1->mAABB.mExtents[2]) * mExtentsCoeff1.z);
- const Point Pb(float(N1->mAABB.mCenter[0]) * mCenterCoeff1.x, float(N1->mAABB.mCenter[1]) * mCenterCoeff1.y, float(N1->mAABB.mCenter[2]) * mCenterCoeff1.z);
- // Perform collision query
- _Collide(N0, N1, a, Pa, b, Pb);
- UPDATE_CACHE
- return true;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Collision query for quantized no-leaf AABB trees.
- * \param tree0 [in] AABB tree from first object
- * \param tree1 [in] AABB tree from second object
- * \param world0 [in] world matrix for first object
- * \param world1 [in] world matrix for second object
- * \param cache [in/out] cache for a pair of previously colliding primitives
- * \return true if success
- * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- bool AABBTreeCollider::Collide(const AABBQuantizedNoLeafTree* tree0, const AABBQuantizedNoLeafTree* tree1, const Matrix4x4* world0, const Matrix4x4* world1, Pair* cache)
- {
- // Init collision query
- InitQuery(world0, world1);
- // Check previous state
- if(CheckTemporalCoherence(cache)) return true;
- // Setup dequantization coeffs
- mCenterCoeff0 = tree0->mCenterCoeff;
- mExtentsCoeff0 = tree0->mExtentsCoeff;
- mCenterCoeff1 = tree1->mCenterCoeff;
- mExtentsCoeff1 = tree1->mExtentsCoeff;
- // Perform collision query
- _Collide(tree0->GetNodes(), tree1->GetNodes());
- UPDATE_CACHE
- return true;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Standard trees
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // The normal AABB tree can use 2 different descent rules (with different performances)
- //#define ORIGINAL_CODE //!< UNC-like descent rules
- #define ALTERNATIVE_CODE //!< Alternative descent rules
- #ifdef ORIGINAL_CODE
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive collision query for normal AABB trees.
- * \param b0 [in] collision node from first tree
- * \param b1 [in] collision node from second tree
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void AABBTreeCollider::_Collide(const AABBCollisionNode* b0, const AABBCollisionNode* b1)
- {
- // Perform BV-BV overlap test
- if(!BoxBoxOverlap(b0->mAABB.mExtents, b0->mAABB.mCenter, b1->mAABB.mExtents, b1->mAABB.mCenter)) return;
- if(b0->IsLeaf() && b1->IsLeaf()) { PrimTest(b0->GetPrimitive(), b1->GetPrimitive()); return; }
- if(b1->IsLeaf() || (!b0->IsLeaf() && (b0->GetSize() > b1->GetSize())))
- {
- _Collide(b0->GetNeg(), b1);
- if(ContactFound()) return;
- _Collide(b0->GetPos(), b1);
- }
- else
- {
- _Collide(b0, b1->GetNeg());
- if(ContactFound()) return;
- _Collide(b0, b1->GetPos());
- }
- }
- #endif
- #ifdef ALTERNATIVE_CODE
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive collision query for normal AABB trees.
- * \param b0 [in] collision node from first tree
- * \param b1 [in] collision node from second tree
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void AABBTreeCollider::_Collide(const AABBCollisionNode* b0, const AABBCollisionNode* b1)
- {
- // Perform BV-BV overlap test
- if(!BoxBoxOverlap(b0->mAABB.mExtents, b0->mAABB.mCenter, b1->mAABB.mExtents, b1->mAABB.mCenter))
- {
- return;
- }
- if(b0->IsLeaf())
- {
- if(b1->IsLeaf())
- {
- PrimTest(b0->GetPrimitive(), b1->GetPrimitive());
- }
- else
- {
- _Collide(b0, b1->GetNeg());
- if(ContactFound()) return;
- _Collide(b0, b1->GetPos());
- }
- }
- else if(b1->IsLeaf())
- {
- _Collide(b0->GetNeg(), b1);
- if(ContactFound()) return;
- _Collide(b0->GetPos(), b1);
- }
- else
- {
- _Collide(b0->GetNeg(), b1->GetNeg());
- if(ContactFound()) return;
- _Collide(b0->GetNeg(), b1->GetPos());
- if(ContactFound()) return;
- _Collide(b0->GetPos(), b1->GetNeg());
- if(ContactFound()) return;
- _Collide(b0->GetPos(), b1->GetPos());
- }
- }
- #endif
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // No-leaf trees
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Leaf-leaf test for two primitive indices.
- * \param id0 [in] index from first leaf-triangle
- * \param id1 [in] index from second leaf-triangle
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void AABBTreeCollider::PrimTest(udword id0, udword id1)
- {
- // Request vertices from the app
- VertexPointers VP0;
- VertexPointers VP1;
- mIMesh0->GetTriangle(VP0, id0);
- mIMesh1->GetTriangle(VP1, id1);
- // Transform from space 1 to space 0
- Point u0,u1,u2;
- TransformPoint(u0, *VP1.Vertex[0], mR1to0, mT1to0);
- TransformPoint(u1, *VP1.Vertex[1], mR1to0, mT1to0);
- TransformPoint(u2, *VP1.Vertex[2], mR1to0, mT1to0);
- // Perform triangle-triangle overlap test
- if(TriTriOverlap(*VP0.Vertex[0], *VP0.Vertex[1], *VP0.Vertex[2], u0, u1, u2))
- {
- // Keep track of colliding pairs
- mPairs.Add(id0).Add(id1);
- // Set contact status
- mFlags |= OPC_CONTACT;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Leaf-leaf test for a previously fetched triangle from tree A (in B's space) and a new leaf from B.
- * \param id1 [in] leaf-triangle index from tree B
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- inline_ void AABBTreeCollider::PrimTestTriIndex(udword id1)
- {
- // Request vertices from the app
- VertexPointers VP;
- mIMesh1->GetTriangle(VP, id1);
- // Perform triangle-triangle overlap test
- if(TriTriOverlap(mLeafVerts[0], mLeafVerts[1], mLeafVerts[2], *VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2]))
- {
- // Keep track of colliding pairs
- mPairs.Add(mLeafIndex).Add(id1);
- // Set contact status
- mFlags |= OPC_CONTACT;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Leaf-leaf test for a previously fetched triangle from tree B (in A's space) and a new leaf from A.
- * \param id0 [in] leaf-triangle index from tree A
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- inline_ void AABBTreeCollider::PrimTestIndexTri(udword id0)
- {
- // Request vertices from the app
- VertexPointers VP;
- mIMesh0->GetTriangle(VP, id0);
- // Perform triangle-triangle overlap test
- if(TriTriOverlap(mLeafVerts[0], mLeafVerts[1], mLeafVerts[2], *VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2]))
- {
- // Keep track of colliding pairs
- mPairs.Add(id0).Add(mLeafIndex);
- // Set contact status
- mFlags |= OPC_CONTACT;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive collision of a leaf node from A and a branch from B.
- * \param b [in] collision node from second tree
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void AABBTreeCollider::_CollideTriBox(const AABBNoLeafNode* b)
- {
- // Perform triangle-box overlap test
- if(!TriBoxOverlap(b->mAABB.mCenter, b->mAABB.mExtents)) return;
- // Keep same triangle, deal with first child
- if(b->HasPosLeaf()) PrimTestTriIndex(b->GetPosPrimitive());
- else _CollideTriBox(b->GetPos());
- if(ContactFound()) return;
- // Keep same triangle, deal with second child
- if(b->HasNegLeaf()) PrimTestTriIndex(b->GetNegPrimitive());
- else _CollideTriBox(b->GetNeg());
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive collision of a leaf node from B and a branch from A.
- * \param b [in] collision node from first tree
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void AABBTreeCollider::_CollideBoxTri(const AABBNoLeafNode* b)
- {
- // Perform triangle-box overlap test
- if(!TriBoxOverlap(b->mAABB.mCenter, b->mAABB.mExtents)) return;
- // Keep same triangle, deal with first child
- if(b->HasPosLeaf()) PrimTestIndexTri(b->GetPosPrimitive());
- else _CollideBoxTri(b->GetPos());
- if(ContactFound()) return;
- // Keep same triangle, deal with second child
- if(b->HasNegLeaf()) PrimTestIndexTri(b->GetNegPrimitive());
- else _CollideBoxTri(b->GetNeg());
- }
- //! Request triangle vertices from the app and transform them
- #define FETCH_LEAF(prim_index, imesh, rot, trans) \
- mLeafIndex = prim_index; \
- /* Request vertices from the app */ \
- VertexPointers VP; imesh->GetTriangle(VP, prim_index); \
- /* Transform them in a common space */ \
- TransformPoint(mLeafVerts[0], *VP.Vertex[0], rot, trans); \
- TransformPoint(mLeafVerts[1], *VP.Vertex[1], rot, trans); \
- TransformPoint(mLeafVerts[2], *VP.Vertex[2], rot, trans);
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive collision query for no-leaf AABB trees.
- * \param a [in] collision node from first tree
- * \param b [in] collision node from second tree
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void AABBTreeCollider::_Collide(const AABBNoLeafNode* a, const AABBNoLeafNode* b)
- {
- // Perform BV-BV overlap test
- if(!BoxBoxOverlap(a->mAABB.mExtents, a->mAABB.mCenter, b->mAABB.mExtents, b->mAABB.mCenter)) return;
- // Catch leaf status
- BOOL BHasPosLeaf = b->HasPosLeaf();
- BOOL BHasNegLeaf = b->HasNegLeaf();
- if(a->HasPosLeaf())
- {
- FETCH_LEAF(a->GetPosPrimitive(), mIMesh0, mR0to1, mT0to1)
- if(BHasPosLeaf) PrimTestTriIndex(b->GetPosPrimitive());
- else _CollideTriBox(b->GetPos());
- if(ContactFound()) return;
- if(BHasNegLeaf) PrimTestTriIndex(b->GetNegPrimitive());
- else _CollideTriBox(b->GetNeg());
- }
- else
- {
- if(BHasPosLeaf)
- {
- FETCH_LEAF(b->GetPosPrimitive(), mIMesh1, mR1to0, mT1to0)
- _CollideBoxTri(a->GetPos());
- }
- else _Collide(a->GetPos(), b->GetPos());
- if(ContactFound()) return;
- if(BHasNegLeaf)
- {
- FETCH_LEAF(b->GetNegPrimitive(), mIMesh1, mR1to0, mT1to0)
- _CollideBoxTri(a->GetPos());
- }
- else _Collide(a->GetPos(), b->GetNeg());
- }
- if(ContactFound()) return;
- if(a->HasNegLeaf())
- {
- FETCH_LEAF(a->GetNegPrimitive(), mIMesh0, mR0to1, mT0to1)
- if(BHasPosLeaf) PrimTestTriIndex(b->GetPosPrimitive());
- else _CollideTriBox(b->GetPos());
- if(ContactFound()) return;
- if(BHasNegLeaf) PrimTestTriIndex(b->GetNegPrimitive());
- else _CollideTriBox(b->GetNeg());
- }
- else
- {
- if(BHasPosLeaf)
- {
- // ### That leaf has possibly already been fetched
- FETCH_LEAF(b->GetPosPrimitive(), mIMesh1, mR1to0, mT1to0)
- _CollideBoxTri(a->GetNeg());
- }
- else _Collide(a->GetNeg(), b->GetPos());
- if(ContactFound()) return;
- if(BHasNegLeaf)
- {
- // ### That leaf has possibly already been fetched
- FETCH_LEAF(b->GetNegPrimitive(), mIMesh1, mR1to0, mT1to0)
- _CollideBoxTri(a->GetNeg());
- }
- else _Collide(a->GetNeg(), b->GetNeg());
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Quantized trees
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive collision query for quantized AABB trees.
- * \param b0 [in] collision node from first tree
- * \param b1 [in] collision node from second tree
- * \param a [in] extent from box A
- * \param Pa [in] center from box A
- * \param b [in] extent from box B
- * \param Pb [in] center from box B
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void AABBTreeCollider::_Collide(const AABBQuantizedNode* b0, const AABBQuantizedNode* b1, const Point& a, const Point& Pa, const Point& b, const Point& Pb)
- {
- // Perform BV-BV overlap test
- if(!BoxBoxOverlap(a, Pa, b, Pb)) return;
- if(b0->IsLeaf() && b1->IsLeaf()) { PrimTest(b0->GetPrimitive(), b1->GetPrimitive()); return; }
- if(b1->IsLeaf() || (!b0->IsLeaf() && (b0->GetSize() > b1->GetSize())))
- {
- // Dequantize box
- const QuantizedAABB* Box = &b0->GetNeg()->mAABB;
- const Point negPa(float(Box->mCenter[0]) * mCenterCoeff0.x, float(Box->mCenter[1]) * mCenterCoeff0.y, float(Box->mCenter[2]) * mCenterCoeff0.z);
- const Point nega(float(Box->mExtents[0]) * mExtentsCoeff0.x, float(Box->mExtents[1]) * mExtentsCoeff0.y, float(Box->mExtents[2]) * mExtentsCoeff0.z);
- _Collide(b0->GetNeg(), b1, nega, negPa, b, Pb);
- if(ContactFound()) return;
- // Dequantize box
- Box = &b0->GetPos()->mAABB;
- const Point posPa(float(Box->mCenter[0]) * mCenterCoeff0.x, float(Box->mCenter[1]) * mCenterCoeff0.y, float(Box->mCenter[2]) * mCenterCoeff0.z);
- const Point posa(float(Box->mExtents[0]) * mExtentsCoeff0.x, float(Box->mExtents[1]) * mExtentsCoeff0.y, float(Box->mExtents[2]) * mExtentsCoeff0.z);
- _Collide(b0->GetPos(), b1, posa, posPa, b, Pb);
- }
- else
- {
- // Dequantize box
- const QuantizedAABB* Box = &b1->GetNeg()->mAABB;
- const Point negPb(float(Box->mCenter[0]) * mCenterCoeff1.x, float(Box->mCenter[1]) * mCenterCoeff1.y, float(Box->mCenter[2]) * mCenterCoeff1.z);
- const Point negb(float(Box->mExtents[0]) * mExtentsCoeff1.x, float(Box->mExtents[1]) * mExtentsCoeff1.y, float(Box->mExtents[2]) * mExtentsCoeff1.z);
- _Collide(b0, b1->GetNeg(), a, Pa, negb, negPb);
- if(ContactFound()) return;
- // Dequantize box
- Box = &b1->GetPos()->mAABB;
- const Point posPb(float(Box->mCenter[0]) * mCenterCoeff1.x, float(Box->mCenter[1]) * mCenterCoeff1.y, float(Box->mCenter[2]) * mCenterCoeff1.z);
- const Point posb(float(Box->mExtents[0]) * mExtentsCoeff1.x, float(Box->mExtents[1]) * mExtentsCoeff1.y, float(Box->mExtents[2]) * mExtentsCoeff1.z);
- _Collide(b0, b1->GetPos(), a, Pa, posb, posPb);
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // Quantized no-leaf trees
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive collision of a leaf node from A and a quantized branch from B.
- * \param leaf [in] leaf triangle from first tree
- * \param b [in] collision node from second tree
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void AABBTreeCollider::_CollideTriBox(const AABBQuantizedNoLeafNode* b)
- {
- // Dequantize box
- const QuantizedAABB* bb = &b->mAABB;
- const Point Pb(float(bb->mCenter[0]) * mCenterCoeff1.x, float(bb->mCenter[1]) * mCenterCoeff1.y, float(bb->mCenter[2]) * mCenterCoeff1.z);
- const Point eb(float(bb->mExtents[0]) * mExtentsCoeff1.x, float(bb->mExtents[1]) * mExtentsCoeff1.y, float(bb->mExtents[2]) * mExtentsCoeff1.z);
- // Perform triangle-box overlap test
- if(!TriBoxOverlap(Pb, eb)) return;
- if(b->HasPosLeaf()) PrimTestTriIndex(b->GetPosPrimitive());
- else _CollideTriBox(b->GetPos());
- if(ContactFound()) return;
- if(b->HasNegLeaf()) PrimTestTriIndex(b->GetNegPrimitive());
- else _CollideTriBox(b->GetNeg());
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive collision of a leaf node from B and a quantized branch from A.
- * \param b [in] collision node from first tree
- * \param leaf [in] leaf triangle from second tree
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void AABBTreeCollider::_CollideBoxTri(const AABBQuantizedNoLeafNode* b)
- {
- // Dequantize box
- const QuantizedAABB* bb = &b->mAABB;
- const Point Pa(float(bb->mCenter[0]) * mCenterCoeff0.x, float(bb->mCenter[1]) * mCenterCoeff0.y, float(bb->mCenter[2]) * mCenterCoeff0.z);
- const Point ea(float(bb->mExtents[0]) * mExtentsCoeff0.x, float(bb->mExtents[1]) * mExtentsCoeff0.y, float(bb->mExtents[2]) * mExtentsCoeff0.z);
- // Perform triangle-box overlap test
- if(!TriBoxOverlap(Pa, ea)) return;
- if(b->HasPosLeaf()) PrimTestIndexTri(b->GetPosPrimitive());
- else _CollideBoxTri(b->GetPos());
- if(ContactFound()) return;
- if(b->HasNegLeaf()) PrimTestIndexTri(b->GetNegPrimitive());
- else _CollideBoxTri(b->GetNeg());
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive collision query for quantized no-leaf AABB trees.
- * \param a [in] collision node from first tree
- * \param b [in] collision node from second tree
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void AABBTreeCollider::_Collide(const AABBQuantizedNoLeafNode* a, const AABBQuantizedNoLeafNode* b)
- {
- // Dequantize box A
- const QuantizedAABB* ab = &a->mAABB;
- const Point Pa(float(ab->mCenter[0]) * mCenterCoeff0.x, float(ab->mCenter[1]) * mCenterCoeff0.y, float(ab->mCenter[2]) * mCenterCoeff0.z);
- const Point ea(float(ab->mExtents[0]) * mExtentsCoeff0.x, float(ab->mExtents[1]) * mExtentsCoeff0.y, float(ab->mExtents[2]) * mExtentsCoeff0.z);
- // Dequantize box B
- const QuantizedAABB* bb = &b->mAABB;
- const Point Pb(float(bb->mCenter[0]) * mCenterCoeff1.x, float(bb->mCenter[1]) * mCenterCoeff1.y, float(bb->mCenter[2]) * mCenterCoeff1.z);
- const Point eb(float(bb->mExtents[0]) * mExtentsCoeff1.x, float(bb->mExtents[1]) * mExtentsCoeff1.y, float(bb->mExtents[2]) * mExtentsCoeff1.z);
- // Perform BV-BV overlap test
- if(!BoxBoxOverlap(ea, Pa, eb, Pb)) return;
- // Catch leaf status
- BOOL BHasPosLeaf = b->HasPosLeaf();
- BOOL BHasNegLeaf = b->HasNegLeaf();
- if(a->HasPosLeaf())
- {
- FETCH_LEAF(a->GetPosPrimitive(), mIMesh0, mR0to1, mT0to1)
- if(BHasPosLeaf) PrimTestTriIndex(b->GetPosPrimitive());
- else _CollideTriBox(b->GetPos());
- if(ContactFound()) return;
- if(BHasNegLeaf) PrimTestTriIndex(b->GetNegPrimitive());
- else _CollideTriBox(b->GetNeg());
- }
- else
- {
- if(BHasPosLeaf)
- {
- FETCH_LEAF(b->GetPosPrimitive(), mIMesh1, mR1to0, mT1to0)
- _CollideBoxTri(a->GetPos());
- }
- else _Collide(a->GetPos(), b->GetPos());
- if(ContactFound()) return;
- if(BHasNegLeaf)
- {
- FETCH_LEAF(b->GetNegPrimitive(), mIMesh1, mR1to0, mT1to0)
- _CollideBoxTri(a->GetPos());
- }
- else _Collide(a->GetPos(), b->GetNeg());
- }
- if(ContactFound()) return;
- if(a->HasNegLeaf())
- {
- FETCH_LEAF(a->GetNegPrimitive(), mIMesh0, mR0to1, mT0to1)
- if(BHasPosLeaf) PrimTestTriIndex(b->GetPosPrimitive());
- else _CollideTriBox(b->GetPos());
- if(ContactFound()) return;
- if(BHasNegLeaf) PrimTestTriIndex(b->GetNegPrimitive());
- else _CollideTriBox(b->GetNeg());
- }
- else
- {
- if(BHasPosLeaf)
- {
- // ### That leaf has possibly already been fetched
- FETCH_LEAF(b->GetPosPrimitive(), mIMesh1, mR1to0, mT1to0)
- _CollideBoxTri(a->GetNeg());
- }
- else _Collide(a->GetNeg(), b->GetPos());
- if(ContactFound()) return;
- if(BHasNegLeaf)
- {
- // ### That leaf has possibly already been fetched
- FETCH_LEAF(b->GetNegPrimitive(), mIMesh1, mR1to0, mT1to0)
- _CollideBoxTri(a->GetNeg());
- }
- else _Collide(a->GetNeg(), b->GetNeg());
- }
- }
|