Bullet 物理引擎 详细分析 Dbvt (2)
开始阅读前可以先浏览一下之前框架分析
在物理模拟的场景中, 一个节点首先应该具备2种属性
物理属性 包含 质量,速度,惯性,加速度,角速度,约束,摩擦系数 等
几何属性 形状, 包围体层次,碰撞检测类型掩码。world 变换。
物理属性大部分都在collosionObject 和rigidObjec 这样的类之中。
几何属性则又一次被细分为包围体层次和形状,碰撞检测类型掩码。
为了进一步介绍Dbvt的核心函数 btDbvt::collideTV
必须首先引入btDbvtProxy。btDbvtProxy 继承自 btBroadphaseProxy。
view plaincopy to clipboardprint?
ATTRIBUTE_ALIGNED16(struct) btBroadphaseProxy
{
///optional filtering to cull potential collisions
enum CollisionFilterGroups
{
DefaultFilter = 1,
StaticFilter = 2,
KinematicFilter = 4,
DebrisFilter = 8,
SensorTrigger = 16,
CharacterFilter = 32,
AllFilter = -1 //all bits sets: DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorTrigger
};
void* m_clientObject;//Usually the client btCollisionObject or Rigidbody class
short int m_collisionFilterGroup; //碰撞检测类型
short int m_collisionFilterMask; //碰撞检测类型掩码
void * m_multiSapParentProxy; //sweep and prune broadphase 测试研究用
int m_uniqueId;//m_uniqueId 在重叠节点管理结构中要用到,非必须
btVector3 m_aabbMin; //store the volume
btVector3 m_aabbMax; //store the volume
}
ATTRIBUTE_ALIGNED16(struct) btBroadphaseProxy
{
///optional filtering to cull potential collisions
enum CollisionFilterGroups
{
DefaultFilter = 1,
StaticFilter = 2,
KinematicFilter = 4,
DebrisFilter = 8,
SensorTrigger = 16,
CharacterFilter = 32,
AllFilter = -1 //all bits sets: DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorTrigger
};
void* m_clientObject;//Usually the client btCollisionObject or Rigidbody class
short int m_collisionFilterGroup; //碰撞检测类型
short int m_collisionFilterMask; //碰撞检测类型掩码
void * m_multiSapParentProxy; //sweep and prune broadphase 测试研究用
int m_uniqueId;//m_uniqueId 在重叠节点管理结构中要用到,非必须
btVector3 m_aabbMin; //store the volume
btVector3 m_aabbMax; //store the volume
}
btBroadphaseProxy 基类包含了最基本的碰撞检测类型以及对象本身支持的碰撞检测类型,关于碰撞检测类型的详细描述可以参见bullet手册的第5章节有详细描述。对象可以根据支持的碰撞检测类型选择碰撞的对象。还包含了指向物理属性对象的指针。
再看btDbvtProxy
view plaincopy to clipboardprint?
struct btDbvtProxy : btBroadphaseProxy
{
/* Fields */
btDbvtNode* leaf; //指向Dbvt 中对应的节点
btDbvtProxy* links[2]; //指向双向列表的前后节点 见btDbvtBroadphase分析
int stage; //所处的队列 见btDbvtBroadphase分析
}
struct btDbvtProxy : btBroadphaseProxy
{
/* Fields */
btDbvtNode* leaf; //指向Dbvt 中对应的节点
btDbvtProxy* links[2]; //指向双向列表的前后节点 见btDbvtBroadphase分析
int stage; //所处的队列 见btDbvtBroadphase分析
}
btDbvtProxy 是一个节点,利用了代理的设计模式,连接物理属性节点与几何节点。
本身还是重合节点管理的重要组成部分。然后再看看btDbvtTreeCollider
view plaincopy to clipboardprint?
/* Tree collider */
struct btDbvtTreeCollider : btDbvt::ICollide
{
btDbvtBroadphase* pbp;
btDbvtProxy* proxy;
void Process(const btDbvtNode* n)
{
Process(n,proxy->leaf);
}
}
/* Tree collider */
struct btDbvtTreeCollider : btDbvt::ICollide
{
btDbvtBroadphase* pbp;
btDbvtProxy* proxy;
void Process(const btDbvtNode* n)
{
Process(n,proxy->leaf);
}
}
btDbvtTreeCollider 定义了当两个几何节点在远距状态下碰撞后的处理方法,btDbvt::ICollide 定义的是接口标准btDbvtTreeCollider 是在dbvt下的一个具体实现,开发者也可以根据自己的需要嵌入不同的处理逻辑。proxy代表的是主节点,n代表的是被比较节点。
现在进入主题 btDbvt::collideTV。这个函数的主要算法是遍历所有和目标节点重合的叶子节点,然后使用已有的处理逻辑模块 btDbvtTreeCollider 来处理这两个节点。会引入新的数据结构btHashedOverlappingPairCache,可以参见后续的btDbvtBroadphase分析
view plaincopy to clipboardprint?
btDbvt::collideTV(const btDbvtNode* root,
const btDbvtVolume& vol,
DBVT_IPOLICY)
{
ATTRIBUTE_ALIGNED16(btDbvtVolume) volume(vol);
btAlignedObjectArray<const btDbvtNode*> stack;
stack.resize(0);
stack.reserve(SIMPLE_STACKSIZE); //生成一个栈用来遍历Dbvt
stack.push_back(root); //根节点入栈
do {
const btDbvtNode* n=stack[stack.size()-1]; // 栈顶元素出栈
stack.pop_back(); // 栈顶元素出栈
if(Intersect(n->volume,volume))// 如果这个节点包含了目标节点
{
if(n->isinternal())// 同时是内部节点,则遍历其子树
{
stack.push_back(n->childs[0]); //左孩子入栈
stack.push_back(n->childs[1]); //右孩子入栈
}
else //如果已经是叶子节点
{
policy.Process(n); // 利用既有的处理策略来处理这一对碰撞的节点
}
}
} while(stack.size()>0); // run until all intersect leaf node is visited .
}
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/superwiles/archive/2010/02/23/5318237.aspx