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 );

现在,假设我们有一个函数,它基本上告诉我们给定点是否以某种方式“穿过”平面。

(摩尔伪代码)

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 之间有任何值得一提的实现差异,我们将不胜感激。

4

2 回答 2

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

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

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

于 2013-11-06T09:45:10.537 回答