因此,我正在尝试实现截锥剔除。这里的问题是,在我能做到这一点之前,我需要了解一些事情。
首先,是平面交点:
我的理解是,平面可以由三个点定义;让我们称它们为p0, p1, and p2
。
鉴于此,我们知道可以按如下方式计算平面的法线:
(psuedo代码)
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在实现上有什么不同之处,我们将不胜感激。
3条答案
按热度按时间ogsagwnx1#
hvvq6cgz2#
你的方法大体上是正确的。
通常使用AABB或边界球体,而不是测试任意形状的每个顶点。
然而,对于AABB,在某些情况下,所有的角都在锥体之外,但长方体仍然与锥体相交。保守的解决方案是,如果所有角点都位于至少一个平面的外侧,则仅拒绝长方体。
对于AABB,有一个常见的优化:对于锥体的每个平面,您只需要检查“最近”和“最远”的角,而不是所有的6个角。这方面和总体上的锥体剔除的一个很好的资源是:
http://www.lighthouse3d.com/tutorials/view-frustum-culling/
编辑:这里是另一篇如何找到不完全位于一个平面的外侧,但仍然不与锥体相交的AABB的文章:
http://www.iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm
e5njpo683#
提纲:
这里是一个改编自基本learnopengl tutorial的最小工作示例。
控制台打印每一帧有多少个OBB被剔除: