最近需要做一些碰撞检测相关的东西。AABB是游戏引擎中最常用的碰撞基本体了,具有各种优良的特性。其本身的自交判断很简单(这句话咋恁别扭呢*~*),而且与其它形体的相交判断也不是很复杂。求一点到AABB上的最近点对很常用,也比较简单,代码如下所示:
void ClosestPtPointAABB(const Point& p , const AABB& b , Point& q) { for (int i = 0 ; i < 3 ; ++i) { float v = p[i]; v = max(v , b.min[i]); v = min(v , b.max[i]); q[i] = v; } }
反过来,求一点到AABB上的最远点呢?这个操作可能没有求最近点常用,但是还是会有使用场合的。分析一下可以发现AABB上到另外一点间的最远点其实就是组成其的8个点中的一个,但是该不会要逐个遍历吧,那也太原始了。其实只需要判断一下这个点在AABB中所处的大体位置,然后决定选用那个角点就Okay了。
void FurthestPtPointAABB(const Point& p , const AABB& b , Point& q) { Point minP , maxP , c; minP = b.GetMin(); maxP = b.GetMax(); c = b.GetCenter(); // X q.x = (dstPoint.x > center.x) ? minPos.x : maxPos.x; // Y q.y = (dstPoint.y > center.y) ? minPos.y : maxPos.y; // Z q.z = (dstPoint.z > center.z) ? minPos.z : maxPos.z; }
另外,还有关于计算生成Bounding Sphere的问题。比如对于一个Camera,可能需要从其对应的Frustum来生成一个Sphere作一些特殊目的的使用,比如Culling等。一般的方法(且也是之前用的方法)是直接求出Frustum对应的8个顶点的Average Point,然后得到球体的中心,接着选取该中心到8个顶点中的最远距离做为半径。但是某些情况下这种方法可能会得到极不好的结果,对于不均匀、不规则的Frustum可能会得到灰常巨大的Sphere,可以看下图对于一个2D三角形的说明。
更好的一种方法是先求出包围Frustum的AABB(当然,OBB会更好),然后从此AABB上来计算得到对应的Sphere,这样就会得到稍优化的Sphere。
当然对于计算包围Sphere最精确的方法就是计算出外切圆了,但是这代价就比较大了,应用会有所限制。