2013-11-05 38 views
3

所以,我试图实施截锥体扑杀。这里的事情是,在我能做到这一点之前,我需要了解一些事情。查看截锥体扑灭问题

首先其中,是平面的交点:

我的理解是一个平面可以通过3点来定义;我们称它们为p0, p1, and p2

鉴于此,我们知道这架飞机的正常可如下计算:

(伪代码)

vec3 edge0 = p1 - p0; 
vec3 edge1 = p2 - p0; 

vec3 normal = normalize(cross(edge0, edg1)) // => edge1 X edge2/length(edge1 X edge2); 

现在,让我们说我们有一个函数,它主要是告诉我们,无论是否某个点以某种方式“穿过”飞机。

(moar伪代码)

bool crossesPlane(vec3 plane[3], vec3 point) 
{ 
    vec3 normal = getNormal(plane); // perform same operations as described above 
    float D = dot(-normal, plane[ 0 ]); // plane[ 0 ] is arbitrary - could just as well be the 2nd or 3rd point in the array 

    float dist = dot(normal, point) + D; 

    return dist >= 0; // dist < 0 means we're on the opposite side of the plane's normal. 
} 

这背后的逻辑推理是,由于视图锥台包含六个不同的平面(近,远,左,上,右,下) ,我们希望抓住这六个平面中的每一个,并且基本上将它们“传递”到对于单个点(对于该点来说是一个点,六个测试)的函数crossesPlane()

如果这六个电话中的一个crossesPlane()回报false,然后我们要剔除有问题的点,从而有效地导致点被截锥被淘汰,当然还有点不会被渲染。

问题

  • 这是一个正确的做法,以正确扑杀视图锥台?
  • 如果是这样,将给出一个给定的多边形的顶点的任意列表,并使用这种方法在每个顶点上执行这个测试,是一个有效的方法去实现它?
  • 尽管AABB可以用来替代剔除测试中的多边形/网格,但是它们仍然常用于此场景,它们仍然被认为是“常规”goto方法吗?

注意

如果有任何值得D3D和OpenGL这间提的实现差异,这将是肯定的赞赏。

+0

通常我们做的同质变换检查,对视锥的飞机,从而使比较的对象1,-1等 –

+1

@MarkPing前:真正用于测试各个顶点,而不是像或的AABB边界的形状因为这些形状在同质空间中不再是球形的矩形。因此,AFAIK在视图空间测试更为常见。 – cdoubleplusgood

回答

3
  • 是的,这实质上是用于平截头体剔除点的正确方法。
  • 不,对每个顶点单独执行此测试并不是剔除任意多边形的有效方法。考虑一个与截头体相交的单个非常大的三角形的情况:它的所有顶点都可能在截头体之外,但三角形仍然与截头体相交并应该被渲染。
  • AABB可以用于平截头体剔除,并且通常是一个不错的选择,但是您仍然必须处理AABB的所有顶点都位于平截体以外但与平截体相交的情况。边界球体使得内部/外部测试稍微简单一些,但是它们所包含的对象周围往往有松散的界限。然而这通常是合理的折衷。
2

您的方法通常是正确的。
通常使用AABB或边界球而不是测试任意形状的每个顶点。
但是,对于AABB,有些情况下所有角落都在平截头体之外,但盒子仍与截锥体相交。一个保守的解决方案是如果所有的角落都位于至少一个平面的外侧,则仅拒绝箱子。
AABB有一个常见的优化:对于平截头体的每个平面,只需检查“最近”和“最远”角而不是全部6个角。对于这一点,并视锥一般扑杀一个很好的资源是这样的:
http://www.lighthouse3d.com/tutorials/view-frustum-culling/

编辑: 这是一个更加文章如何找到并不完全是一个一个平面的外侧,但还是不相交的AABB视锥:
http://www.iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm