一旦平面定义好了。那么我们就可以测试点是在视景体之内还是之外。计算符号的距离可以告诉我们点是在平面的哪一边。假设平面的法向是向内的,如果点的符号距离是负的,那么说明点在视景体之外。否则点就在平面的右侧。
下面的类frustumG方法说明了实现的方式,参数就是测试的点:
int FrustumG::pointInFrustum(Vec3 &p) {
int result = INSIDE;
for(int i=0; i < 6; i++) {
if (pl[i].distance(p) < 0)
return OUTSIDE;
}
return(result);
}
注意早期跳出函数的功能性,如果一个点在视景体之内必须在每个平面的右边,因此为了测试一个点,所有的六个平面都要测试。然而,只要点在一个平面的错误边那么就可以拒绝余下平面的测试。
为了测试一个物体,所有点都要测试。如果所有的点都是在平面的错误边那么物体就是视景体之外。然而这对于一个大的模型来说需要很多时间。加上一个小车模型有10000个多边形。在错误的情况下需要做10000次测试才能找到小车相对于视景体的位置。
在这种情况下看来让图形硬件绘制小车比计算所有的测试都要快,然后而且在这上面,可能还是需要绘制这个小车。
因此对于复杂的模型测试所有的顶点并不是一个好的选项,那么就用包围体来代替。现在存在很多种包围体,其中两种最流行的,最简单的,就是球和包围盒。
寻找一个小车的包围球是一件很简单的事情(顶点的中心就是球的中心,半径就是离中心最远的距离),测试一个球体是非常快,将在下面展示。
这边有个改进的地方:虽然测试快速但是缺乏准确性:有可能小车模型都在视景体之外但是包围球部分在视景体之内,简单的测试可能导致视景体之外的模型发送到图形硬件中。但是只要有在包围球和物体之间的比较,这种方式是有所补偿的。
测试球体跟测试点是差不多的,除了球体的半径之外。一个球体如果它的中心至少有一个边的错误边并且到平面的距离大于半径,那么就是在视景体之外。如果距离的绝对值小于半径,那么球体就是跟视景体相交。意味着球体部分在视景体之内。否则就是全部在视景体之内。
int FrustumG::sphereInFrustum(Vec3 &p, float radius) {
float distance;
int result = INSIDE;
for(int i=0; i < 6; i++) {
distance = pl[i].distance(p);
if (distance < -radius)
return OUTSIDE;
else if (distance < radius)
result = INTERSECT;
}
return(result);
}
这个函数接收球体的中心和半径,然后跟所有的边做测试。
英文地址
博客地址:http://www.arcosu.com/post/index/101