Added btGhostObject and btPairCachingGhostObject functionality.

It is a fast way to keep track of overlapping objects in an area, and doing rayTest and convexSweepTest for overlapping objects, instead of btCollisionWorld::rayTest/convexSweepTest.

Updated KinematicCharacterController to use btPairCachingGhostObject.
This commit is contained in:
erwin.coumans
2008-10-18 01:33:23 +00:00
parent 7f52613c45
commit 4cbb3f2e7b
14 changed files with 488 additions and 569 deletions

View File

@@ -33,7 +33,8 @@ int gFindPairs =0;
btHashedOverlappingPairCache::btHashedOverlappingPairCache():
m_overlapFilterCallback(0),
m_blockedForChanges(false)
m_blockedForChanges(false),
m_ghostPairCallback(0)
{
int initialAllocatedSize= 2;
m_overlappingPairArray.reserve(initialAllocatedSize);
@@ -238,6 +239,11 @@ btBroadphasePair* btHashedOverlappingPairCache::internalAddPair(btBroadphaseProx
int count = m_overlappingPairArray.size();
int oldCapacity = m_overlappingPairArray.capacity();
void* mem = &m_overlappingPairArray.expand();
//this is where we add an actual pair, so also call the 'ghost'
if (m_ghostPairCallback)
m_ghostPairCallback->addOverlappingPair(proxy0,proxy1);
int newCapacity = m_overlappingPairArray.capacity();
if (oldCapacity < newCapacity)
@@ -317,6 +323,9 @@ void* btHashedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* pro
int lastPairIndex = m_overlappingPairArray.size() - 1;
if (m_ghostPairCallback)
m_ghostPairCallback->removeOverlappingPair(proxy0, proxy1,dispatcher);
// If the removed pair is the last pair, we are done.
if (lastPairIndex == pairIndex)
{
@@ -399,6 +408,8 @@ void* btSortedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* pro
btBroadphasePair& pair = m_overlappingPairArray[findIndex];
void* userData = pair.m_userInfo;
cleanOverlappingPair(pair,dispatcher);
if (m_ghostPairCallback)
m_ghostPairCallback->removeOverlappingPair(proxy0, proxy1,dispatcher);
m_overlappingPairArray.swap(findIndex,m_overlappingPairArray.capacity()-1);
m_overlappingPairArray.pop_back();
@@ -426,8 +437,12 @@ btBroadphasePair* btSortedOverlappingPairCache::addOverlappingPair(btBroadphaseP
void* mem = &m_overlappingPairArray.expand();
btBroadphasePair* pair = new (mem) btBroadphasePair(*proxy0,*proxy1);
gOverlappingPairs++;
gAddedPairs++;
if (m_ghostPairCallback)
m_ghostPairCallback->addOverlappingPair(proxy0, proxy1);
return pair;
}
@@ -493,7 +508,8 @@ void btSortedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback*
btSortedOverlappingPairCache::btSortedOverlappingPairCache():
m_blockedForChanges(false),
m_hasDeferredRemoval(true),
m_overlapFilterCallback(0)
m_overlapFilterCallback(0),
m_ghostPairCallback(0)
{
int initialAllocatedSize= 2;
m_overlappingPairArray.reserve(initialAllocatedSize);

View File

@@ -83,6 +83,8 @@ public:
virtual bool hasDeferredRemoval() = 0;
virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback)=0;
};
/// Hash-space based Pair Cache, thanks to Erin Catto, Box2D, http://www.box2d.org, and Pierre Terdiman, Codercorner, http://codercorner.com
@@ -253,10 +255,16 @@ private:
return false;
}
virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback)
{
m_ghostPairCallback = ghostPairCallback;
}
public:
btAlignedObjectArray<int> m_hashTable;
btAlignedObjectArray<int> m_next;
btOverlappingPairCallback* m_ghostPairCallback;
};
@@ -280,6 +288,8 @@ class btSortedOverlappingPairCache : public btOverlappingPairCache
//if set, use the callback instead of the built in filter in needBroadphaseCollision
btOverlapFilterCallback* m_overlapFilterCallback;
btOverlappingPairCallback* m_ghostPairCallback;
public:
btSortedOverlappingPairCache();
@@ -355,12 +365,17 @@ class btSortedOverlappingPairCache : public btOverlappingPairCache
return m_hasDeferredRemoval;
}
virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback)
{
m_ghostPairCallback = ghostPairCallback;
}
};
///btNullPairCache skips add/removal of overlapping pairs. Userful for benchmarking and testing.
///btNullPairCache skips add/removal of overlapping pairs. Userful for benchmarking and unit testing.
class btNullPairCache : public btOverlappingPairCache
{
@@ -414,6 +429,10 @@ public:
return true;
}
virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback)
{
}
virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* /*proxy0*/,btBroadphaseProxy* /*proxy1*/)
{
return 0;
@@ -427,6 +446,7 @@ public:
virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* /*proxy0*/,btDispatcher* /*dispatcher*/)
{
}
};

View File

@@ -17,7 +17,6 @@ subject to the following restrictions:
#define COLLISION_CREATE_FUNC
#include "LinearMath/btAlignedObjectArray.h"
typedef btAlignedObjectArray<class btCollisionObject*> btCollisionObjectArray;
class btCollisionAlgorithm;
class btCollisionObject;

View File

@@ -29,8 +29,11 @@ struct btBroadphaseProxy;
class btCollisionShape;
#include "LinearMath/btMotionState.h"
#include "LinearMath/btAlignedAllocator.h"
#include "LinearMath/btAlignedObjectArray.h"
typedef btAlignedObjectArray<class btCollisionObject*> btCollisionObjectArray;
/// btCollisionObject can be used to manage collision detection objects.
/// btCollisionObject maintains all information that is needed for a collision detection: Shape, Transform and AABB proxy.

View File

@@ -71,7 +71,7 @@ class btBroadphaseInterface;
#include "LinearMath/btVector3.h"
#include "LinearMath/btTransform.h"
#include "btCollisionObject.h"
#include "btCollisionDispatcher.h" //for definition of btCollisionObjectArray
#include "btCollisionDispatcher.h"
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
#include "LinearMath/btAlignedObjectArray.h"

View File

@@ -14,16 +14,149 @@ subject to the following restrictions:
*/
#include "btGhostObject.h"
#include "btCollisionWorld.h"
#include "BulletCollision/CollisionShapes/btConvexShape.h"
#include "LinearMath/btAabbUtil2.h"
btGhostObject::btGhostObject()
{
m_internalType = CO_GHOST_OBJECT;
m_overlappingPairCache = new (btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16)) btHashedOverlappingPairCache();
m_overlappingPairCache->setOverlapFilterCallback(&m_ghostOverlapFilterCallback);
}
btGhostObject::~btGhostObject()
{
btAlignedFree(m_overlappingPairCache);
///btGhostObject should have been removed from the world, so no overlapping objects
btAssert(!m_overlappingObjects.size());
}
void btGhostObject::addOverlappingObject(btBroadphaseProxy* otherProxy)
{
btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject;
btAssert(otherObject);
int index = m_overlappingObjects.findLinearSearch(otherObject);
if (index==m_overlappingObjects.size())
{
m_overlappingObjects.push_back(otherObject);
}
}
void btGhostObject::removeOverlappingObject(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher)
{
btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject;
btAssert(otherObject);
int index = m_overlappingObjects.findLinearSearch(otherObject);
if (index<m_overlappingObjects.size())
{
m_overlappingObjects[index] = m_overlappingObjects[m_overlappingObjects.size()-1];
m_overlappingObjects.pop_back();
}
}
btPairCachingGhostObject::btPairCachingGhostObject()
{
m_hashPairCache = new (btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16)) btHashedOverlappingPairCache();
}
btPairCachingGhostObject::~btPairCachingGhostObject()
{
btAlignedFree( m_hashPairCache );
}
void btPairCachingGhostObject::addOverlappingObject(btBroadphaseProxy* otherProxy)
{
btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject;
btAssert(otherObject);
int index = m_overlappingObjects.findLinearSearch(otherObject);
if (index==m_overlappingObjects.size())
{
m_overlappingObjects.push_back(otherObject);
m_hashPairCache->addOverlappingPair(getBroadphaseHandle(),otherProxy);
}
}
void btPairCachingGhostObject::removeOverlappingObject(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher)
{
btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject;
btAssert(otherObject);
int index = m_overlappingObjects.findLinearSearch(otherObject);
if (index<m_overlappingObjects.size())
{
m_overlappingObjects[index] = m_overlappingObjects[m_overlappingObjects.size()-1];
m_overlappingObjects.pop_back();
m_hashPairCache->removeOverlappingPair(getBroadphaseHandle(),otherProxy,dispatcher);
}
}
void btGhostObject::convexSweepTest(const btConvexShape* castShape, const btTransform& convexFromWorld, const btTransform& convexToWorld, btScalar allowedCcdPenetration, btCollisionWorld::ConvexResultCallback& resultCallback) const
{
btTransform convexFromTrans,convexToTrans;
convexFromTrans = convexFromWorld;
convexToTrans = convexToWorld;
btVector3 castShapeAabbMin, castShapeAabbMax;
/* Compute AABB that encompasses angular movement */
{
btVector3 linVel, angVel;
btTransformUtil::calculateVelocity (convexFromTrans, convexToTrans, 1.0, linVel, angVel);
btTransform R;
R.setIdentity ();
R.setRotation (convexFromTrans.getRotation());
castShape->calculateTemporalAabb (R, linVel, angVel, 1.0, castShapeAabbMin, castShapeAabbMax);
}
/// go over all objects, and if the ray intersects their aabb + cast shape aabb,
// do a ray-shape query using convexCaster (CCD)
int i;
for (i=0;i<m_overlappingObjects.size();i++)
{
btCollisionObject* collisionObject= m_overlappingObjects[i];
//only perform raycast if filterMask matches
if(resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) {
//RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject();
btVector3 collisionObjectAabbMin,collisionObjectAabbMax;
collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax);
AabbExpand (collisionObjectAabbMin, collisionObjectAabbMax, castShapeAabbMin, castShapeAabbMax);
btScalar hitLambda = btScalar(1.); //could use resultCallback.m_closestHitFraction, but needs testing
btVector3 hitNormal;
if (btRayAabb(convexFromWorld.getOrigin(),convexToWorld.getOrigin(),collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,hitNormal))
{
btCollisionWorld::objectQuerySingle(castShape, convexFromTrans,convexToTrans,
collisionObject,
collisionObject->getCollisionShape(),
collisionObject->getWorldTransform(),
resultCallback,
allowedCcdPenetration);
}
}
}
}
void btGhostObject::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const
{
btTransform rayFromTrans;
rayFromTrans.setIdentity();
rayFromTrans.setOrigin(rayFromWorld);
btTransform rayToTrans;
rayToTrans.setIdentity();
rayToTrans.setOrigin(rayToWorld);
int i;
for (i=0;i<m_overlappingObjects.size();i++)
{
btCollisionObject* collisionObject= m_overlappingObjects[i];
//only perform raycast if filterMask matches
if(resultCallback.needsCollision(collisionObject->getBroadphaseHandle()))
{
btCollisionWorld::rayTestSingle(rayFromTrans,rayToTrans,
collisionObject,
collisionObject->getCollisionShape(),
collisionObject->getWorldTransform(),
resultCallback);
}
}
}

View File

@@ -21,8 +21,11 @@ subject to the following restrictions:
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h"
#include "LinearMath/btAlignedAllocator.h"
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
#include "btCollisionWorld.h"
///work-in-progress, not complete
class btConvexShape;
class btDispatcher;
///The btGhostObject can keep track of all objects that are overlapping
///By default, this overlap is based on the AABB
@@ -32,20 +35,7 @@ ATTRIBUTE_ALIGNED16(class) btGhostObject : public btCollisionObject
{
protected:
btOverlappingPairCache* m_overlappingPairCache;
struct btGhostOverlapFilterCallback : public btOverlapFilterCallback
{
bool needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const
{
bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0;
collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
return collides;
}
};
btGhostOverlapFilterCallback m_ghostOverlapFilterCallback;
btAlignedObjectArray<btCollisionObject*> m_overlappingObjects;
public:
@@ -53,33 +43,41 @@ public:
virtual ~btGhostObject();
void convexSweepTest(const class btConvexShape* castShape, const btTransform& convexFromWorld, const btTransform& convexToWorld, btScalar allowedCcdPenetration,btCollisionWorld::ConvexResultCallback& resultCallback) const;
virtual void addOverlappingObject(btCollisionObject* otherObject);
void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const;
virtual void removeOverlappingObject(btCollisionObject* otherObject);
virtual void addOverlappingObject(btBroadphaseProxy* otherProxy);
btOverlappingPairCache* getPairCache()
virtual void removeOverlappingObject(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher);
int getNumOverlappingObjects() const
{
return m_overlappingPairCache;
};
const btOverlappingPairCache* getPairCache() const
{
return m_overlappingPairCache;
};
btBroadphasePairArray& getOverlappingPairArray()
{
return m_overlappingPairCache->getOverlappingPairArray();
return m_overlappingObjects.size();
}
btOverlappingPairCache* getOverlappingPairCache()
btCollisionObject* getOverlappingObject(int index)
{
return m_overlappingPairCache;
return m_overlappingObjects[index];
}
const btCollisionObject* getOverlappingObject(int index) const
{
return m_overlappingObjects[index];
}
btAlignedObjectArray<btCollisionObject*>& getOverlappingPairs()
{
return m_overlappingObjects;
}
const btAlignedObjectArray<btCollisionObject*> getOverlappingPairs() const
{
return m_overlappingObjects;
}
//
// Cast
// internal cast
//
static const btGhostObject* upcast(const btCollisionObject* colObj)
@@ -95,11 +93,31 @@ public:
return 0;
}
};
class btPairCachingGhostObject : public btGhostObject
{
btHashedOverlappingPairCache* m_hashPairCache;
public:
btPairCachingGhostObject();
virtual ~btPairCachingGhostObject();
virtual void addOverlappingObject(btBroadphaseProxy* otherProxy);
virtual void removeOverlappingObject(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher);
btHashedOverlappingPairCache* getOverlappingPairCache()
{
return m_hashPairCache;
}
};
///btGhostPairCache keeps track of overlapping objects that have AABB overlap with the ghost
class btGhostPairCallback : public btOverlappingPairCallback
{
@@ -121,9 +139,10 @@ public:
btGhostObject* ghost0 = btGhostObject::upcast(colObj0);
btGhostObject* ghost1 = btGhostObject::upcast(colObj1);
if (ghost0)
ghost0->addOverlappingObject(colObj1);
ghost0->addOverlappingObject(proxy1);
if (ghost1)
ghost1->addOverlappingObject(colObj0);
ghost1->addOverlappingObject(proxy0);
return 0;
}
virtual void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher)
@@ -133,9 +152,10 @@ public:
btGhostObject* ghost0 = btGhostObject::upcast(colObj0);
btGhostObject* ghost1 = btGhostObject::upcast(colObj1);
if (ghost0)
ghost0->removeOverlappingObject(colObj1);
ghost0->removeOverlappingObject(proxy1,dispatcher);
if (ghost1)
ghost1->removeOverlappingObject(colObj0);
ghost1->removeOverlappingObject(proxy0,dispatcher);
return 0;
}
virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy0,btDispatcher* dispatcher)

View File

@@ -19,7 +19,7 @@ subject to the following restrictions:
#include "BulletCollision/CollisionDispatch/btUnionFind.h"
#include "btCollisionCreateFunc.h"
#include "LinearMath/btAlignedObjectArray.h"
#include "btCollisionObject.h"
class btCollisionObject;
class btCollisionWorld;