📄 opc_treecollider.cpp
字号:
#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
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool AABBTreeCollider::Collide(const AABBCollisionTree* tree0, const AABBCollisionTree* tree1, const IceMaths::Matrix4x4* world0, const IceMaths::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
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool AABBTreeCollider::Collide(const AABBNoLeafTree* tree0, const AABBNoLeafTree* tree1, const IceMaths::Matrix4x4* world0, const IceMaths::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
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool AABBTreeCollider::Collide(const AABBQuantizedTree* tree0, const AABBQuantizedTree* tree1, const IceMaths::Matrix4x4* world0, const IceMaths::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 IceMaths::Point a(float(N0->mAABB.mExtents[0]) * mExtentsCoeff0.x, float(N0->mAABB.mExtents[1]) * mExtentsCoeff0.y, float(N0->mAABB.mExtents[2]) * mExtentsCoeff0.z);
const IceMaths::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 IceMaths::Point b(float(N1->mAABB.mExtents[0]) * mExtentsCoeff1.x, float(N1->mAABB.mExtents[1]) * mExtentsCoeff1.y, float(N1->mAABB.mExtents[2]) * mExtentsCoeff1.z);
const IceMaths::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
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool AABBTreeCollider::Collide(const AABBQuantizedNoLeafTree* tree0, const AABBQuantizedNoLeafTree* tree1, const IceMaths::Matrix4x4* world0, const IceMaths::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 (applies scale 1 to u0u1u2)
IceMaths::Point u0,u1,u2;
TransformPoint(u0, *VP1.Vertex[0], mSR1to0, mT1to0);
TransformPoint(u1, *VP1.Vertex[1], mSR1to0, mT1to0);
TransformPoint(u2, *VP1.Vertex[2], mSR1to0, mT1to0);
// Perform triangle-triangle overlap test (includes scale 0 to v0v1v2)
if(TriTriOverlap((*VP0.Vertex[0])*mScale0, (*VP0.Vertex[1])*mScale0, (*VP0.Vertex[2])*mScale0, 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 (uses mScale1)
if(TriTriOverlap(mLeafVerts[0], mLeafVerts[1], mLeafVerts[2], *VP.Vertex[0]*mScale1, *VP.Vertex[1]*mScale1, *VP.Vertex[2]*mScale1))
{
// 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 (uses mScale0)
if(TriTriOverlap(mLeafVerts[0], mLeafVerts[1], mLeafVerts[2], *VP.Vertex[0]*mScale0, *VP.Vertex[1]*mScale0, *VP.Vertex[2]*mScale0))
{
// 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 (applies mScale1 on the box first!)
if(!TriBoxOverlap(b->mAABB.mCenter*mScale1, b->mAABB.mExtents*mScale1)) 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -