collide*系列的函数,比如collideTV就是Tree和Volume的
collideTV
深度优先遍历Tree,如果某个node和Volume相交,且是叶子节点,则调用回调函数
collideTT
,测试两个树,和TV不同的是:
- TT每次往栈压入的是一对节点,取出也是一对节点,
sStkNN
,用这个保存一对节点指针 - 如果取出的两个节点相交:
- 如果取出的两个节点都是非叶子节点,则将他们的左右孩子对,共4种节点对组合压入栈中
- 如果取出的两个节点一个是叶子,一个是非叶子,则压入叶子和非叶子左右孩子的节点对
- 只有取出的两个节点都是叶子节点时,才调回调
- 特殊的,如果取出的两个节点是一个且是非叶子,则将它自己的左右孩子对,共3中组合压入
collideKDOP
测试树和k-DOP相交。
// count是k-DOP面的个数,normals和offset确定了这些面
void collideKDOP(const btDbvtNode* root, const btVector3* normals, const btScalar* offsets, int count, DBVT_IPOLICY)
{
DBVT_CHECKTYPE
if(root)
{
// inside的每一位都是1,表示aabb都在k-DOP的count个面的同侧,或者说aabb在k-DOP里面
const int inside=(1<<count)-1;
btAlignedObjectArray<sStkNP> stack;
int signs[sizeof(unsigned)*8];
btAssert(count<int (sizeof(signs)/sizeof(signs[0])));
for(int i=0;i<count;++i)
{
signs[i]= ((normals[i].x()>=0)?1:0)+
((normals[i].y()>=0)?2:0)+
((normals[i].z()>=0)?4:0);
}
stack.reserve(SIMPLE_STACKSIZE);
stack.push_back(sStkNP(root,0));
do {
sStkNP se=stack[stack.size()-1];
bool out=false;
stack.pop_back();
for(int i=0,j=1;(!out)&&(i<count);++i,j<<=1)
{
// mask的第j位是1表明aabb在第j个面的同侧
if(0==(se.mask&j))
{
// 测试aabb和面的关系。其实这个函数我没看懂。。。
const int side=se.node->volume.Classify(normals[i], offsets[i], signs[i]);
switch(side)
{
// 如果aabb在某一个面的异侧,说明aabb完全在k-DOP外
case -1: out=true;break;
// 如果aabb在某一个面的同侧,设置标志位
case +1: se.mask|=j;break;
}
}
}
if(!out)
{
// 如果:
// 1. 当前的aabb已经是叶子,则调回调
// 2. 当前的aabb完全在k-DOP里面,则遍历他的全部叶子节点并调回调
// 否则继续深度优先遍历树
if((se.mask!=inside)&&(se.node->isinternal()))
{
// aabb和k-DOP每个面是否同侧的关系被他的孩子继承
stack.push_back(sStkNP(se.node->childs[0], se.mask));
stack.push_back(sStkNP(se.node->childs[1], se.mask));
}
else
{
if(policy.AllLeaves(se.node)) enumLeaves(se.node, policy);
}
}
} while(stack.size());
}
}