查看视锥体剔除问题

时间:2013-11-05 05:51:55

标签: opengl 3d computer-science computational-geometry direct3d

所以,我正在努力实施视锥体剔除。这里的事情是,在我能做到之前,我需要了解一些事情。

首先是平面交叉点:

我的理解是可以通过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之间存在任何值得一提的实现差异,那么肯定会受到赞赏。

2 个答案:

答案 0 :(得分:3)

  • 是的,这实际上是截头剔除点的正确方法。
  • 不,单独对每个顶点执行此测试不是剔除任意多边形的有效方法。考虑一个与平截头体相交的单个非常大的三角形的情况:它的所有顶点都可能在平截头体之外,但三角形仍然与平截头体相交并且应该被渲染。
  • AABB可以用于视锥体剔除,并且通常是一个不错的选择,尽管你仍然需要处理AABB的情况,它的所有顶点都在截锥体之外但与截锥体相交。边界球使内部/外部测试更简单,但往往在它们包含的对象周围有更宽松的边界。然而,这通常是一个合理的权衡。

答案 1 :(得分:2)

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

编辑: 这是另外一篇文章,如何找到不完全是一个平面外侧的AABB,但仍然不与平截头体相交:
http://www.iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm

相关问题