OpenGL Clip Space Frustum剔除错误的结果

时间:2012-12-05 19:42:58

标签: opengl

我在CPU上实现了Clip-Space Frustum剔除。 在一个简单的简化案例中,我只是根据4个不同的点创建一个矩形,我将在GL_LINES模式中渲染。

但有时候,在我看来,我得到了错误的结果。这是一个例子:

http://s7.directupload.net/images/121205/imawbhoh.png

在这个渲染过程中,我的平截头体剔除计算检测到,所有点都在NDC坐标中的正y坐标之外。

这是输入:

点数:

P1: -5000, 3, -5000
P2: -5000, 3,  5000
P3:  5000, 3,  5000
P4:  5000, 3, -5000

MVP(舍入):

  1.0550   0.0000  -1.4521   1138.9092
 -1.1700   1.9331  -0.8500  -6573.4885
 -0.6481  -0.5993  -0.4708  -2129.3858
 -0.6478  -0.5990  -0.4707  -2108.5455

计算(MVP *位置)

P1       P2       P3       P4
3124     -11397   -847     13674
3532     -4968    -16668   -8168
3463     -1245    -7726    -3018
3482     -1225    -7703    -2996

最后,通过视角划分(w-component)

进行转换
P1       P2       P3       P4
0.897    9.304    0.110    -4.564
1.014    4.056    2.164    2.726
0.995    1.016    1.003    1.007
1.0      1.0      1.0      1.0

如您所见,所有变换点的y分量都大于1,并且应该在Viewing Frustum之外。

我已经仔细检查了我的矩阵。我还在Vertex Shader中做了一个变换反馈,以确保,我在CPU和GPU上使用相同的矩阵进行计算。即使MVP * Point的结果在我的顶点着色器中与在GPU上相同。我的渲染管道尽可能简单。

顶点着色器是

vColor = aColor; 
gl_Position = MVP * aVertexPosition;

//With Transform Feedback enabled
//transOut = MVP * aVertexPosition

碎片Shader

FragColor = vColor;

因此Vertex Shader与我的CPU计算结果相同。 但是,它们仍然是在屏幕上绘制的线条! 任何想法为什么有线? 我是否对透视鸿沟做错了什么?

我必须做什么来检测这个矩形不应该被剔除,因为至少有一条线是可见的(在这个例子中基本上是另一条线的条带也是可见的)

如果有帮助:可见红线是P1和P2之间的那条......

[编辑] 现在,我通过计算相机平截头体法线和正常形式方程来实现世界空间剔除。这可以正确识别。遗憾的是,我确实需要在剪辑空间中进行正确的计算,因为我将使用这些点进行其他计算。有人有什么想法吗?

这是我的计算代码:

int outOfBoundArray[6] = {0, 0, 0, 0, 0, 0};
std::vector<glm::dvec4> tileBounds = activeElem->getTileBounds(); //Same as I use for world space culling
const glm::dmat4& viewProj = cam->getCameraTransformations().viewProjectionMatrix; //Same camera which I use for world space culling.

for (int i=0; i<tileBounds.size(); i++) {

    //Apply ModelViewProjection Matrix, to Clip Space
    glm::dvec4 transformVec = viewProj * tileBounds[i];

    //To NDC space [-1,1]
    transformVec = transformVec / transformVec[3];

    //Culling test
    if ( transformVec.x >  1.0 ) outOfBoundArray[0]++;
    if ( transformVec.x < -1.0 ) outOfBoundArray[1]++;
    if ( transformVec.y >  1.0 ) outOfBoundArray[2]++;
    if ( transformVec.y < -1.0 ) outOfBoundArray[3]++;
    if ( transformVec.z >  1.0 ) outOfBoundArray[4]++;
    if ( transformVec.z < -1.0 ) outOfBoundArray[5]++;

    //Other computations...
}

for (int i=0; i<6; i++) {
    if (outOfBoundArray[i] == tileBounds.size()) {
        return false;
    }
}
return true;

1 个答案:

答案 0 :(得分:1)

问题似乎是w(第三个成分)的符号在P1和P2之间是不同的。由于投影几何的性质,这将导致各种麻烦。

即使点位于NDC的同一侧,绘制的线实际上也会通​​过无穷大:考虑当您在P1和P2之间进行线性插值并在每个点分别用w进行除法时会发生什么。会发生的是当w接近零时,y值不完全为零,因此该线缩小到无穷大。然后从另一边缠绕。

投影几何是一个奇怪的事情:)

但是,对于一个解决方案,请确保在该平面的正面剪切穿过w = 0平面的那些线,然后设置 - 您的代码应该可以正常工作。