Bullet 学习笔记之 btCollisionWorld

对于 Bullet 物理引擎中的碰撞检测部分,并不太关心它的实现细节,更想知道的是物体的存储方式/数据存放、碰撞结果在哪儿,大致的步骤等


1、碰撞场景类 btCollisionWorld 的结构

btCollisionWorld 是 Bullet 物理引擎中的碰撞场景类,并由此派生出了 btDynamicsWorld 以及进一步派生出 btDiscreteDynamicsWorld btSoftRigidDynamicsWorld 等。

先从 btCollisionWorld 的成员变量/函数分析它的碰撞算法/数据存储:

btAlignedObjectArray<btCollisionObject*> m_collisionObjects;

btDispatcher* m_dispatcher1;

btDispatcherInfo m_dispatchInfo;

btBroadphaseInterface* m_broadphasePairCache;

主要成员变量有这么四个。其中,m_collisionObjects 是存放场景中的物体。m_dispatcher1 是用于 narrowphase collision detection 的,即,用于精确碰撞检测,(其中,通过 btDispatcher 类可知,最终的碰撞检测结果,也是存放在 dispatcher 中的 btPersistentManifold 或者 user callbacks。)另,m_dispatchInfo 是精确碰撞检测的一些配置信息。m_broadphasePairCache 则应该是用于 broadphase collision detection 的,最终形成可能的碰撞对 overlappinng pairs 。


2、碰撞场景 btCollisionWorld 的初始化/搭建

接下来看,btCollisionWorld 类的初始化过程,以及在 Basic Example 中,都是怎么配置 btCollisionWorld 的。

在构造函数中,分别对 m_dispatcher1m_broadphasePairCache 进行了初始化。参见 BasicDemo 中的例子,初始化阶段:

m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);    // --> m_dispatcher1

m_broadphase = new btDbvtBroadphase();    // --> m_broadphasePairCache

那么,broad phase 是由 btDbvtBroadphase 类完成的,并将所检测到的 overlapping pairs 存储在其当中; narrow phase 则是由 btCollisionDispatcher 类完成的,并将最终检测到的碰撞点信息存放在 btPersistentManifold 中。

此外,对于场景中的碰撞对象的添加、删除、访问,可以通过以下函数实现:

virtual void addCollisionObject(btCollisionObject* collisionObject, int collisionFilterGroup = btBroadphaseProxy::DefaultFilter, int collisionFilterMask = btBroadphaseProxy::AllFilter);

virtual void removeCollisionObject(btCollisionObject* collisionObject);

btCollisionObjectArray& getCollisionObjectArray()
{
	return m_collisionObjects;
}

const btCollisionObjectArray& getCollisionObjectArray() const
{
	return m_collisionObjects;
}

3、碰撞检测方式/过程

接下来,大致看一下碰撞检测过程,以及碰撞的到的结果(),是存放在什么地方,又是如何被进一步调用的。

在文章 Ron Ngai:[Bullet3]三种碰撞检测及实现 中提到,Bullet 物理引擎可以实现三种方式的碰撞检测:(1)btCollisionWorld::contactTest 检测指定对象是否与场景发生碰撞;(2)btCollisionWorld::performDiscreteCollisionDetection 检测场景中所有物体的碰撞;(3)btCollisionWorld::rayTest 对场景中的所有物体进行射线碰撞检测。

也可以这么说,btCollisionWorld 类可以实现以下几种碰撞检测方式:

  • 3.1、对场景中所有物体进行碰撞
    具体来说,是通过调用函数 btCollisionWorld::performDiscreteCollisionDetection() 实现。

  • 3.2、对场景中所有物体进行射线碰撞检测
    调用函数 btCollisionWorld::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) 完成。对于检测到的结果,可以分为 first hit, all hits, any hit 等,通过调用 resultCallback 可以对结果进行处理。(其实还有一个,可以对一个给定的射线、给定的对像,进行碰撞检测。)具体函数为:

/// rayTest performs a raycast on all objects in the btCollisionWorld, and calls the resultCallback
/// This allows for several queries: first hit, all hits, any hit, dependent on the value returned by the callback.
virtual void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const;

/// rayTestSingle performs a raycast call and calls the resultCallback. It is used internally by rayTest.
/// In a future implementation, we consider moving the ray test as a virtual method in btCollisionShape.
/// This allows more customization.
static void rayTestSingle(const btTransform& rayFromTrans, const btTransform& rayToTrans,
			btCollisionObject* collisionObject,
			const btCollisionShape* collisionShape,
			const btTransform& colObjWorldTransform,
			RayResultCallback& resultCallback);
  • 3.3、给定对象与场景中所有对象的碰撞检测
    包括了两个函数,具体为:
///contactTest performs a discrete collision test between colObj against all objects in the btCollisionWorld, and calls the resultCallback.
///it reports one or more contact points for every overlapping object (including the one with deepest penetration)
void contactTest(btCollisionObject* colObj, ContactResultCallback& resultCallback);

///contactTest performs a discrete collision test between two collision objects and calls the resultCallback if overlap if detected.
///it reports one or more contact points (including the one with deepest penetration)
void contactPairTest(btCollisionObject* colObjA, btCollisionObject* colObjB, ContactResultCallback& resultCallback);

  • 3.4、Convex Sweep Test
    感觉应该是,给定一个 convex 对象,在场景中从 from 运动至 to ,该过程中会发生哪些碰撞,结果包括 first hit, all hits, any hit。碰撞结果可以由 resultCallback 访问并处理。具体函数为:
/// convexTest performs a swept convex cast on all objects in the btCollisionWorld, and calls the resultCallback
/// This allows for several queries: first hit, all hits, any hit, dependent on the value return by the callback.
void convexSweepTest(const btConvexShape* castShape, const btTransform& from, const btTransform& to, ConvexResultCallback& resultCallback, btScalar allowedCcdPenetration = btScalar(0.)) const;

4、碰撞结果存储及处理

对于 btCollisionWorld 中不同的碰撞检测方式(如3.1 - 3.4所述),其结果的存放/处理也不尽相同。就逐个分析一下吧

  • 4.1 对场景中所有物体进行碰撞 - 碰撞结果存放及处理

  • 4.2 对场景中所有物体进行射线碰撞检测 - 碰撞检测结果存放及处理

  • 4.3、给定对象与场景中所有对象的碰撞检测 - 碰撞结果存放及处理

  • 4.4、Convex Sweep Test - 碰撞结果存放及处理


5、结语

xxx。

猜你喜欢

转载自www.cnblogs.com/wghou09/p/12819204.html