bullet入门-DBvt树的raycast

Posted by ysd on August 10, 2017

一些基础的东西

ICollide接口

声明了一些回调函数,检测到两个节点碰撞后调用。bullet里还有一些默认的实现。
比如btDbvtTreeCollider::Process就将两个节点放到btDbvtBroadphase的碰撞对缓存btOverlappingPairCache

btDbvtProxy

继承btBroadphaseProxy,定义了一个object可以和哪些group的object碰撞,以及自己属于哪个group

aabb树的raycast

和树中的每个aabb测试,如果成功:如果是叶子节点,则执行回调;否则深度优先搜索孩子节点

aabb的raycast

bool btRayAabb2(const btVector3& rayFrom,
const btVector3& rayInvDirection, // 射线方向的倒数

const unsigned int raySign[3], // 射线三个分量的符号,负数是1,正数是0,便于区分射线起点离aabb两个相对的面的哪个更近

const btVector3 bounds[2],
btScalar& tmin,
btScalar lambda_min, // 0

btScalar lambda_max) // 射线长度

{
btScalar tmax, tymin, tymax, tzmin, tzmax;
tmin = (bounds[raySign[0]].getX() - rayFrom.getX()) * rayInvDirection.getX(); // 射入x的

tmax = (bounds[1-raySign[0]].getX() - rayFrom.getX()) * rayInvDirection.getX(); // 射出x的

tymin = (bounds[raySign[1]].getY() - rayFrom.getY()) * rayInvDirection.getY(); // 射入y的

tymax = (bounds[1-raySign[1]].getY() - rayFrom.getY()) * rayInvDirection.getY();// 射出y的


if ( (tmin > tymax) || (tymin > tmax) )
return false;

if (tymin > tmin)
tmin = tymin;

if (tymax < tmax)
tmax = tymax;

tzmin = (bounds[raySign[2]].getZ() - rayFrom.getZ()) * rayInvDirection.getZ();
tzmax = (bounds[1-raySign[2]].getZ() - rayFrom.getZ()) * rayInvDirection.getZ();

if ( (tmin > tzmax) || (tzmin > tmax) )
return false;
if (tzmin > tmin)
tmin = tzmin;
if (tzmax < tmax)
tmax = tzmax;
return ( (tmin < lambda_max) && (tmax > lambda_min) ); // t要比0大,比射线长度小。t小于0说明射线是原理aabb的

}

Slabs method算法

总共4个表示射线的长度,分别是射入x=x0、射出x=x1、射入y=y0、射出y=y1的长度
如果射出的两个长度中较小的(tmax),大于 射入的两个长度中较大的(tmin),则有可能相交
求射线的长度:
光线的参数方程为R(t) = O + t * Dir, t就是射线的长度
一般平面方程为aX+bY+cZ+d=0,因为AABB的六个面分别平行于XY、XZ、YZ平面,所以平面的方程为X=d,Y=d,Z=d
光线与垂直于x轴的两个面相交时,t = (d - O.x) / Dir.x
光线与垂直于y轴的两个面相交时,t = (d - O.y) / Dir.y
光线与垂直于z轴的两个面相交时,t = (d - O.z) / Dir.z