Added btNearCallback. This is similar to Open Dynamics Engine (ODE) dNearCallback, but important differences:

- contact points are persistent (lifetime more then one frame, for warmstarting/incremental contact point management)
- continuous collision detection, time of impact
Added btRigidBody::isInWorld(), returns true if btRigidBody is inside a btCollisionWorld/btDynamicsWorld derived class
Added angularFactor to btRigidbody, this helps some character control (no angular impulse applied)
This commit is contained in:
ejcoumans
2006-12-04 15:42:03 +00:00
parent 2f557b2a4d
commit b6d1b4c94e
8 changed files with 142 additions and 90 deletions

View File

@@ -16,6 +16,7 @@ subject to the following restrictions:
//#define PRINT_CONTACT_STATISTICS 1 //#define PRINT_CONTACT_STATISTICS 1
//#define REGISTER_CUSTOM_COLLISION_ALGORITHM 1 //#define REGISTER_CUSTOM_COLLISION_ALGORITHM 1
//#define USER_DEFINED_FRICTION_MODEL 1 //#define USER_DEFINED_FRICTION_MODEL 1
#define USE_CUSTOM_NEAR_CALLBACK 1
//following define allows to compare/replace Bullet's constraint solver with ODE quickstep //following define allows to compare/replace Bullet's constraint solver with ODE quickstep
//this define requires to either add the libquickstep library (win32, see msvc/8/libquickstep.vcproj) or manually add the files from Extras/quickstep //this define requires to either add the libquickstep library (win32, see msvc/8/libquickstep.vcproj) or manually add the files from Extras/quickstep
@@ -110,6 +111,42 @@ btCollisionShape* shapePtr[numShapes] =
//by default, Bullet will use its own nearcallback, but you can override it using dispatcher->setNearCallback()
void customNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, btDispatcherInfo& dispatchInfo)
{
btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
if (dispatcher.needsCollision(colObj0,colObj1))
{
//dispatcher will keep algorithms persistent in the collision pair
if (!collisionPair.m_algorithm)
{
collisionPair.m_algorithm = dispatcher.findAlgorithm(colObj0,colObj1);
}
if (collisionPair.m_algorithm)
{
btManifoldResult contactPointResult(colObj0,colObj1);
if (dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE)
{
//discrete collision detection query
collisionPair.m_algorithm->processCollision(colObj0,colObj1,dispatchInfo,&contactPointResult);
} else
{
//continuous collision detection query, time of impact (toi)
float toi = collisionPair.m_algorithm->calculateTimeOfImpact(colObj0,colObj1,dispatchInfo,&contactPointResult);
if (dispatchInfo.m_timeOfImpact > toi)
dispatchInfo.m_timeOfImpact = toi;
}
}
}
}
@@ -254,6 +291,11 @@ void CcdPhysicsDemo::initPhysics()
btCollisionDispatcher* dispatcher = new btCollisionDispatcher(); btCollisionDispatcher* dispatcher = new btCollisionDispatcher();
#ifdef USE_CUSTOM_NEAR_CALLBACK
//this is optional
dispatcher->setNearCallback(customNearCallback);
#endif
btVector3 worldAabbMin(-10000,-10000,-10000); btVector3 worldAabbMin(-10000,-10000,-10000);
btVector3 worldAabbMax(10000,10000,10000); btVector3 worldAabbMax(10000,10000,10000);

View File

@@ -70,7 +70,8 @@ struct btBroadphaseProxy
StaticFilter = 2, StaticFilter = 2,
KinematicFilter = 4, KinematicFilter = 4,
DebrisFilter = 8, DebrisFilter = 8,
AllFilter = DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter, SensorTrigger = 16,
AllFilter = DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorTrigger,
}; };
//Usually the client btCollisionObject or Rigidbody class //Usually the client btCollisionObject or Rigidbody class
@@ -118,8 +119,7 @@ class btCollisionAlgorithm;
struct btBroadphaseProxy; struct btBroadphaseProxy;
//Increase SIMPLE_MAX_ALGORITHMS to allow multiple btDispatchers caching their own algorithms
#define SIMPLE_MAX_ALGORITHMS 1
/// contains a pair of aabb-overlapping objects /// contains a pair of aabb-overlapping objects
struct btBroadphasePair struct btBroadphasePair
@@ -127,22 +127,16 @@ struct btBroadphasePair
btBroadphasePair () btBroadphasePair ()
: :
m_pProxy0(0), m_pProxy0(0),
m_pProxy1(0) m_pProxy1(0),
m_algorithm(0)
{ {
for (int i=0;i<SIMPLE_MAX_ALGORITHMS;i++)
{
m_algorithms[i] = 0;
}
} }
btBroadphasePair(const btBroadphasePair& other) btBroadphasePair(const btBroadphasePair& other)
: m_pProxy0(other.m_pProxy0), : m_pProxy0(other.m_pProxy0),
m_pProxy1(other.m_pProxy1) m_pProxy1(other.m_pProxy1),
m_algorithm(other.m_algorithm)
{ {
for (int i=0;i<SIMPLE_MAX_ALGORITHMS;i++)
{
m_algorithms[i] = other.m_algorithms[i];
}
} }
btBroadphasePair(btBroadphaseProxy& proxy0,btBroadphaseProxy& proxy1) btBroadphasePair(btBroadphaseProxy& proxy0,btBroadphaseProxy& proxy1)
{ {
@@ -159,17 +153,14 @@ struct btBroadphasePair
m_pProxy1 = &proxy0; m_pProxy1 = &proxy0;
} }
for (int i=0;i<SIMPLE_MAX_ALGORITHMS;i++) m_algorithm = 0;
{
m_algorithms[i] = 0;
}
} }
btBroadphaseProxy* m_pProxy0; btBroadphaseProxy* m_pProxy0;
btBroadphaseProxy* m_pProxy1; btBroadphaseProxy* m_pProxy1;
mutable btCollisionAlgorithm* m_algorithms[SIMPLE_MAX_ALGORITHMS]; mutable btCollisionAlgorithm* m_algorithm;
}; };

View File

@@ -22,11 +22,6 @@ class btRigidBody;
class btCollisionObject; class btCollisionObject;
class btOverlappingPairCache; class btOverlappingPairCache;
enum btCollisionDispatcherId
{
RIGIDBODY_DISPATCHER = 0,
USERCALLBACK_DISPATCHER
};
class btPersistentManifold; class btPersistentManifold;
class btStackAlloc; class btStackAlloc;
@@ -74,11 +69,6 @@ public:
virtual btCollisionAlgorithm* findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold=0) = 0; virtual btCollisionAlgorithm* findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold=0) = 0;
//
// asume dispatchers to have unique id's in the range [0..max dispacher]
//
virtual int getUniqueId() = 0;
virtual btPersistentManifold* getNewManifold(void* body0,void* body1)=0; virtual btPersistentManifold* getNewManifold(void* body0,void* body1)=0;
virtual void releaseManifold(btPersistentManifold* manifold)=0; virtual void releaseManifold(btPersistentManifold* manifold)=0;

View File

@@ -54,14 +54,11 @@ void btOverlappingPairCache::removeOverlappingPair(btBroadphasePair& findPair)
void btOverlappingPairCache::cleanOverlappingPair(btBroadphasePair& pair) void btOverlappingPairCache::cleanOverlappingPair(btBroadphasePair& pair)
{ {
for (int dispatcherId=0;dispatcherId<SIMPLE_MAX_ALGORITHMS;dispatcherId++) if (pair.m_algorithm)
{ {
if (pair.m_algorithms[dispatcherId])
{ {
{ delete pair.m_algorithm;;
delete pair.m_algorithms[dispatcherId]; pair.m_algorithm=0;
pair.m_algorithms[dispatcherId]=0;
}
} }
} }
} }

View File

@@ -45,6 +45,8 @@ m_emptyCreateFunc(0)
{ {
int i; int i;
setNearCallback(defaultNearCallback);
m_emptyCreateFunc = new btEmptyAlgorithm::CreateFunc; m_emptyCreateFunc = new btEmptyAlgorithm::CreateFunc;
for (i=0;i<MAX_BROADPHASE_COLLISION_TYPES;i++) for (i=0;i<MAX_BROADPHASE_COLLISION_TYPES;i++)
{ {
@@ -62,6 +64,8 @@ btCollisionDispatcher::btCollisionDispatcher ():
{ {
int i; int i;
setNearCallback(defaultNearCallback);
//default CreationFunctions, filling the m_doubleDispatch table //default CreationFunctions, filling the m_doubleDispatch table
m_convexConvexCreateFunc = new btConvexConvexAlgorithm::CreateFunc; m_convexConvexCreateFunc = new btConvexConvexAlgorithm::CreateFunc;
m_convexConcaveCreateFunc = new btConvexConcaveCollisionAlgorithm::CreateFunc; m_convexConcaveCreateFunc = new btConvexConcaveCollisionAlgorithm::CreateFunc;
@@ -275,50 +279,20 @@ class btCollisionPairCallback : public btOverlapCallback
{ {
btDispatcherInfo& m_dispatchInfo; btDispatcherInfo& m_dispatchInfo;
btCollisionDispatcher* m_dispatcher; btCollisionDispatcher* m_dispatcher;
int m_dispatcherId;
public: public:
btCollisionPairCallback(btDispatcherInfo& dispatchInfo,btCollisionDispatcher* dispatcher,int dispatcherId) btCollisionPairCallback(btDispatcherInfo& dispatchInfo,btCollisionDispatcher* dispatcher)
:m_dispatchInfo(dispatchInfo), :m_dispatchInfo(dispatchInfo),
m_dispatcher(dispatcher), m_dispatcher(dispatcher)
m_dispatcherId(dispatcherId)
{ {
} }
virtual bool processOverlap(btBroadphasePair& pair) virtual bool processOverlap(btBroadphasePair& pair)
{ {
btCollisionObject* body0 = (btCollisionObject*)pair.m_pProxy0->m_clientObject; (*m_dispatcher->getNearCallback())(pair,*m_dispatcher,m_dispatchInfo);
btCollisionObject* body1 = (btCollisionObject*)pair.m_pProxy1->m_clientObject;
if (!m_dispatcher->needsCollision(body0,body1))
return false;
//dispatcher will keep algorithms persistent in the collision pair
if (!pair.m_algorithms[m_dispatcherId])
{
pair.m_algorithms[m_dispatcherId] = m_dispatcher->findAlgorithm(
body0,
body1);
}
if (pair.m_algorithms[m_dispatcherId])
{
btManifoldResult* resultOut = m_dispatcher->internalGetNewManifoldResult(body0,body1);
if (m_dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE)
{
pair.m_algorithms[m_dispatcherId]->processCollision(body0,body1,m_dispatchInfo,resultOut);
} else
{
float toi = pair.m_algorithms[m_dispatcherId]->calculateTimeOfImpact(body0,body1,m_dispatchInfo,resultOut);
if (m_dispatchInfo.m_timeOfImpact > toi)
m_dispatchInfo.m_timeOfImpact = toi;
}
m_dispatcher->internalReleaseManifoldResult(resultOut);
}
return false; return false;
} }
}; };
@@ -327,9 +301,7 @@ void btCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pa
{ {
//m_blockedForChanges = true; //m_blockedForChanges = true;
int dispatcherId = getUniqueId(); btCollisionPairCallback collisionCallback(dispatchInfo,this);
btCollisionPairCallback collisionCallback(dispatchInfo,this,dispatcherId);
pairCache->processAllOverlappingPairs(&collisionCallback); pairCache->processAllOverlappingPairs(&collisionCallback);
@@ -338,3 +310,39 @@ void btCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pa
} }
//by default, Bullet will use this near callback
void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, btDispatcherInfo& dispatchInfo)
{
btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
if (dispatcher.needsCollision(colObj0,colObj1))
{
//dispatcher will keep algorithms persistent in the collision pair
if (!collisionPair.m_algorithm)
{
collisionPair.m_algorithm = dispatcher.findAlgorithm(colObj0,colObj1);
}
if (collisionPair.m_algorithm)
{
btManifoldResult contactPointResult(colObj0,colObj1);
if (dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE)
{
//discrete collision detection query
collisionPair.m_algorithm->processCollision(colObj0,colObj1,dispatchInfo,&contactPointResult);
} else
{
//continuous collision detection query, time of impact (toi)
float toi = collisionPair.m_algorithm->calculateTimeOfImpact(colObj0,colObj1,dispatchInfo,&contactPointResult);
if (dispatchInfo.m_timeOfImpact > toi)
dispatchInfo.m_timeOfImpact = toi;
}
}
}
}

View File

@@ -32,6 +32,10 @@ class btOverlappingPairCache;
#define USE_DISPATCH_REGISTRY_ARRAY 1 #define USE_DISPATCH_REGISTRY_ARRAY 1
class btCollisionDispatcher;
///user can override this nearcallback for collision filtering and more finegrained control over collision detection
typedef void (*btNearCallback)(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, btDispatcherInfo& dispatchInfo);
///btCollisionDispatcher supports algorithms that handle ConvexConvex and ConvexConcave collision pairs. ///btCollisionDispatcher supports algorithms that handle ConvexConvex and ConvexConcave collision pairs.
///Time of Impact, Closest Points and Penetration Depth. ///Time of Impact, Closest Points and Penetration Depth.
@@ -44,6 +48,8 @@ class btCollisionDispatcher : public btDispatcher
btManifoldResult m_defaultManifoldResult; btManifoldResult m_defaultManifoldResult;
btNearCallback m_nearCallback;
btCollisionAlgorithmCreateFunc* m_doubleDispatch[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES]; btCollisionAlgorithmCreateFunc* m_doubleDispatch[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES];
btCollisionAlgorithmCreateFunc* internalFindCreateFunc(int proxyType0,int proxyType1); btCollisionAlgorithmCreateFunc* internalFindCreateFunc(int proxyType0,int proxyType1);
@@ -62,18 +68,6 @@ class btCollisionDispatcher : public btDispatcher
public: public:
///allows the user to get contact point callbacks
inline btManifoldResult* internalGetNewManifoldResult(btCollisionObject* obj0,btCollisionObject* obj1)
{
//in-place, this prevents parallel dispatching, but just adding a list would fix that.
btManifoldResult* manifoldResult = new (&m_defaultManifoldResult) btManifoldResult(obj0,obj1);
return manifoldResult;
}
///allows the user to get contact point callbacks
inline void internalReleaseManifoldResult(btManifoldResult*)
{
}
///registerCollisionCreateFunc allows registration of custom/alternative collision create functions ///registerCollisionCreateFunc allows registration of custom/alternative collision create functions
void registerCollisionCreateFunc(int proxyType0,int proxyType1, btCollisionAlgorithmCreateFunc* createFunc); void registerCollisionCreateFunc(int proxyType0,int proxyType1, btCollisionAlgorithmCreateFunc* createFunc);
@@ -122,11 +116,20 @@ public:
virtual bool needsResponse(btCollisionObject* body0,btCollisionObject* body1); virtual bool needsResponse(btCollisionObject* body0,btCollisionObject* body1);
virtual int getUniqueId() { return RIGIDBODY_DISPATCHER;}
virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,btDispatcherInfo& dispatchInfo); virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,btDispatcherInfo& dispatchInfo);
void setNearCallback(btNearCallback nearCallback)
{
m_nearCallback = nearCallback;
}
btNearCallback getNearCallback() const
{
return m_nearCallback;
}
//by default, Bullet will use this near callback
static void defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, btDispatcherInfo& dispatchInfo);
}; };

View File

@@ -35,6 +35,7 @@ btRigidBody::btRigidBody(float mass, btMotionState* motionState, btCollisionShap
m_totalTorque(0.0f, 0.0f, 0.0f), m_totalTorque(0.0f, 0.0f, 0.0f),
m_linearVelocity(0.0f, 0.0f, 0.0f), m_linearVelocity(0.0f, 0.0f, 0.0f),
m_angularVelocity(0.f,0.f,0.f), m_angularVelocity(0.f,0.f,0.f),
m_angularFactor(1.f),
m_linearDamping(0.f), m_linearDamping(0.f),
m_angularDamping(0.5f), m_angularDamping(0.5f),
m_optionalMotionState(motionState), m_optionalMotionState(motionState),

View File

@@ -47,6 +47,7 @@ class btRigidBody : public btCollisionObject
btVector3 m_linearVelocity; btVector3 m_linearVelocity;
btVector3 m_angularVelocity; btVector3 m_angularVelocity;
btScalar m_inverseMass; btScalar m_inverseMass;
btScalar m_angularFactor;
btVector3 m_gravity; btVector3 m_gravity;
btVector3 m_invInertiaLocal; btVector3 m_invInertiaLocal;
@@ -159,7 +160,10 @@ public:
if (m_inverseMass != 0.f) if (m_inverseMass != 0.f)
{ {
applyCentralImpulse(impulse); applyCentralImpulse(impulse);
applyTorqueImpulse(rel_pos.cross(impulse)); if (m_angularFactor)
{
applyTorqueImpulse(rel_pos.cross(impulse)*m_angularFactor);
}
} }
} }
@@ -169,7 +173,10 @@ public:
if (m_inverseMass != 0.f) if (m_inverseMass != 0.f)
{ {
m_linearVelocity += linearComponent*impulseMagnitude; m_linearVelocity += linearComponent*impulseMagnitude;
m_angularVelocity += angularComponent*impulseMagnitude; if (m_angularFactor)
{
m_angularVelocity += angularComponent*impulseMagnitude*m_angularFactor;
}
} }
} }
@@ -321,7 +328,20 @@ public:
int m_contactSolverType; int m_contactSolverType;
int m_frictionSolverType; int m_frictionSolverType;
void setAngularFactor(float angFac)
{
m_angularFactor = angFac;
}
float getAngularFactor() const
{
return m_angularFactor;
}
//is this rigidbody added to a btCollisionWorld/btDynamicsWorld/btBroadphase?
bool isInWorld() const
{
return (getBroadphaseProxy() != 0);
}
int m_debugBodyId; int m_debugBodyId;
}; };