Bullet提供了三种简单的方法来筛选需要检测碰撞的物体:mask,broadphase过滤器回调和Nearcallbacks。mask的性能成本要远远低于回调。简而言之,如果mask足以满足您的需求,使用它们;他们表现更好,使用起来也更简单。当然,也不要仅仅因为他们性能稍好,就把明显不合适的功能塞给mask来做。callback的性能也只是稍差而已。
使用掩码 mask
Bullet支持位操作掩码(int32,最多32类物体),来决定物体是否应该和别的物体碰撞,或者接收碰撞。
int myGroup = 1;
int collideMask = 4;
world->addCollisionObject(object,myGroup,collideMask);
在粗略检测阶段,只有掩码和另一类型物体的group匹配时,才会将重叠的物体算作碰撞(在needsBroadphaseCollision方法中)。从代码看,这是双向的。
bool collides =
(proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0;
collides = collides
&& (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
如果您的对象类型多于掩码中可用的32位,或者基于其他因素来启用或禁用碰撞,那么可以通过几个方法注册回调函数,实现自定义过滤逻辑,在函数中决定哪些类型的物体需要碰撞:
碰撞过滤之 Broadphase Filter Callback
粗略检测阶段利用回调过滤碰撞也是很有效的,可以在碰撞检测的早期阶段就过滤掉不必要的物体。
struct YourOwnFilterCallback : public btOverlapFilterCallback
{
// return true when pairs need collision
virtual bool needBroadphaseCollision(btBroadphaseProxy *proxy0, btBroadphaseProxy *proxy1) const
{
//这是默认逻辑
bool collides =
(proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0;
collides = collides
&& (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
//add some additional logic here that modified 'collides',
//以下可以添加自定义逻辑
return collides;
}
};
然后,创建这个过滤器的对象,并且注册到world对象里。
btOverlapFilterCallback * filterCallback = new YourOwnFilterCallback();
dynamicsWorld->getPairCache()->setOverlapFilterCallback(filterCallback);
碰撞过滤之 :NearCallback
与上一节类似,只不过这个阶段发生在NarrowPhase(在粗略之后)。The btCollisionDispatcher::dispatchAllCollisionPairs calls this
narrowphase nearcallback for each pair that passes the
‘btCollisionDispatcher::needsCollision’ test. You can customize this nearcallback:
void MyNearCallback(btBroadphasePair& collisionPair,
btCollisionDispatcher& dispatcher, btDispatcherInfo& dispatchInfo) {
// Do your collision logic here 自定义过滤逻辑
// Only dispatch the Bullet collision information if you want the physics to continue
// 如果需要碰撞,调用以下方法
dispatcher.defaultNearCallback(collisionPair, dispatcher, dispatchInfo);
}
mDispatcher->setNearCallback(MyNearCallback);
碰撞过滤之终极杀器:自定义btCollisionDispatcher
如果需要更细粒度的碰撞派发,可以集成btCollisionDispatcher,并实现以下方法:
virtual bool needsCollision(btCollisionObject* body0,btCollisionObject* body1);
virtual bool needsResponse(btCollisionObject* body0,btCollisionObject* body1);
virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const
btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher) ;
最后
对于我们而言,掩码和粗略检测时的回调,已经足够了,没必要自定义btCollisionDispatcher。