球体与平面间的测试
令球体S中心位置为C,半径为r,且平面P由方程(n·X)=d定义,其中n为单位向量,即|n|=1.将球心代入平面方程,结果为球心距平面的有符号距离。
球体是否与平面相交
//Determine whether plane p intersects sphere s
bool TestSpherePlane(Sphere s, Plane p)
{
//For a normalized plane (|p.n|=1),evaluating the plane equation
//for a point gives the signed distance of the point to the plane
float dist = Dot(s.c, p.n) – p.d;
//If sphere center within +/- radius from plane, plane intersects sphere
return Abs(dist) <= s.r;
}
球体是否完全位于平面背面
//Determine whether sphere s is fully behind (inside negative half space of) plane p
bool InsideSpherePlane(Sphere s, Plane p)
{
float dist = Dot(s.c , p.n) - p.d;
return dist < -s.r;
}
球体是否与平面负半空间相交
//Determine whether sphere s intersects negative half space of p
bool TestSphereHalfspace(Sphere s, Plane p)
{
float dist = Dot(s.c, p.n) - p.d;
return dist <= s.r;
}
盒体与平面间的测试
令平面P由方程(n·X) = d定义,则盒体B与平面P的相交测试可以采用分离轴测试,且只需测试与平面法向量n平行的轴即可。如下图:
判断OBB与平面是否相交只需判断各顶点V至中心点C线段投影最大值r是否超过平面至中心点距离s即可。
OBB中的8个顶点V可以表示为V=C+/-e0u0+/-e1u1+/-e2u2。
r的计算可表示为r = (V-C)·n
则r最大值为r = ( e0|u0·n| + e1|u1·n| + e2|u2·n| )
若n不是单位向量,则r = ( e0|u0·n| + e1|u1·n| + e2|u2·n| )/|n|
可将C代入P方程可得C距P有符号距离s,s = n·C - d。
当-r <= s <= r时两者相交。
以下代码中,n不必须为单位向量。若n不为单位向量,则r和s相当于同时增加了一个系数|n|,对比较没有影响。
//Test if OBB b intersects plane p
int TestOBBPlane(OBB b, Plane p)
{
//Compute the projection interval radius of b onto L(t) = b.c + t*p.n
float r = b.e[0]*Abs(Dot(p.n,b.u[0])) +
b.e[1]*Abs(Dot(p.n,b.u[1])) +
b.e[2]*Abs(Dot(p.n,b.u[2])) ;
//Compute distance of box center from plane
float s = Dot(p.n, b.c) - p.d;
//Intersection occurs when distance s falls within [-r,+r] interval
return Abs(s) <= r;
}
其他测试可以采用类似方法加以实现:若s <= -r,则OBB位于平面负半空间;若r<=s,则OBB完全位于平面正半空间。
对于AABB代码如下:
//Test if AABB b intersects plane p
int TestAABBPlane(AABB b, Plane p)
{
//These two lines not necessary with a (center, extends) AABB representation
Point c = (b.max + b.min) * 0.5f; //Compute AABB center
Point e = b.max - c; //Compute positive extends
//Compute the projection interval radius of b onto L(t) = b.c + t * p.n
float r = e[0] * Abs(p.n[0]) + e[1] * Abs(p.n[1]) + e[2] * Abs(p.n[2]);
//Compute distance of box center from plane
float s = Dot(p.n, c) - d;
//Intersection occurs when distance s falls within [-r,+r] interval
return Abs(s) <= r;
}
锥体与平面间的测试
给定平面(n·X) = d。定义一个锥体,其中锥顶为T,单位轴向为d,高度为h,底面半径为r。若锥体中存在一点且位于平面的负半空间,即对于锥体中一点X且有(n·X) < d,则锥体与平面的负半空间相交。对于上诉条件,只需测试锥体中两点:
锥顶T;
位于锥体底面上且沿-n方向的最远点Q。
对于第二个测试
Q = T+hd + rm
其中,向量m = Cross(Cross(n, d), d);
若Cross(n, d)为0向量,则d与n平行,m也为0向量,此时求出的Q为底面圆圆心,不影响测试。
若仅测试平面本身而非半平面相交测试,则当锥顶点位于平面背面时,Q改为计算沿n方向的最远顶点(锥顶点位于正面时,Q仍计算沿-n方向最远顶点)。相交测试转换为是否位于平面两侧,即计算(n·T) - d和(n·Q) - d是否有不同符号。