Boundingbox的两个决定点:
//! The near edge
vector3d<T> MinEdge;
//! The far edge
vector3d<T> MaxEdge;
计算BB的中心:(返回的是BB的中心点)
vector3d<T> getCenter() const
{
return (MinEdge + MaxEdge) / 2;
}
计算BB大小:(返回的是BB的对角线向量, xyz分别是BB的各边长)
vector3d<T> getExtent() const
{
return MaxEdge - MinEdge;
}
与线段的交叉检测(这时长方体的中心已经被变换到坐标系原点, 线段也已经变换到BB空间):
bool intersectsWithLine(const vector3d<T>& linemiddle,//线段中心点
const vector3d<T>& linevect,//线段的单位向量
T halflength) const//一半的 线段长度
{
const vector3d<T> e = getExtent() * (T)0.5;//一半的对角线向量
const vector3d<T> t = getCenter() - linemiddle;//线段中心到BB中心的向量
if ((fabs(t.X) > e.X + halflength * fabs(linevect.X)) ||
(fabs(t.Y) > e.Y + halflength * fabs(linevect.Y)) ||
(fabs(t.Z) > e.Z + halflength * fabs(linevect.Z)) )
return false;
e是一半的对角线向量, e的xyz分别是长方体的一半长宽高,也就是中心到各个面的距离.
t是从线段中心指向BB中心的向量.这样很明显看出,在第一步,先简单检测, 如果
|t.x| = |Cx| > |e.x| + |LineProjOnX|/2 = |e.x| + |Wx|那么在X方向上不相交. 然后是在YZ两个方向上用相同的判断.
图:<<3D图形学中的光线和包围盒相交检测>> Pu Jiantao ([email protected])
在YZ平面: 如果X方向上相交,从BB中心向线段做垂线(向量a) :
a = W X (1,0,0) = (0, Wz, - Wy);
这里W = linevect.那么a = linevect X (1,0,0) = (0, linevect.z, -linevect.y);
t在a上的投影(BB中心到线段的距离) :
d = t*a = (t.x, t.y, t.z)*(0, linevect.z, -linevect.y) = |t.y*linevect.z - t.z*linevect.y|
同理, e在平行于linevect而过点(0, hy, hz)的直线L2上有一个投影r, 这个投影的距离用来和d做判断:
r = e * linevect = e.Y * linevect.Z + e.Z * linevect.Y
如果d < r则不相交.其它两个平面上的投影也是如此计算.
T r = e.Y * (T)fabs(linevect.Z) + e.Z * (T)fabs(linevect.Y);
if (fabs(t.Y*linevect.Z - t.Z*linevect.Y) > r )
return false;
r = e.X * (T)fabs(linevect.Z) + e.Z * (T)fabs(linevect.X);
if (fabs(t.Z*linevect.X - t.X*linevect.Z) > r )
return false;
r = e.X * (T)fabs(linevect.Y) + e.Y * (T)fabs(linevect.X);
if (fabs(t.X*linevect.Y - t.Y*linevect.X) > r)
return false;
return true;
}