c++ - OpenGL 剪辑空间视锥体剔除错误结果

标签 c++ opengl glm-math

我在 CPU 上实现了剪辑空间视锥体剔除。 在一个简单的简化案例中,我只创建一个基于 4 个不同点的矩形,我将在 GL_LINES 模式下渲染它们。

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

在此渲染过程中,我的视锥体剔除计算检测到,所有点都将位于 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-分量)进行转换

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,并且应位于视锥体之外。

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

顶点着色器是

vColor = aColor; 
gl_Position = MVP * aVertexPosition;

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

以及片段着色器

FragColor = vColor;

所以顶点着色器的结果与我的 CPU 计算的结果相同。 但它们仍然是屏幕上绘制的线条! 有什么想法为什么会有线条吗? 我在视角鸿沟方面做错了什么吗?

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

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

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

这是我的计算代码:

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;

最佳答案

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

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

射影几何是一件奇怪的事情:)

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

关于c++ - OpenGL 剪辑空间视锥体剔除错误结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13731133/

相关文章:

c++ - 隐式转换为 basic_istream/ifstream/ofstream 的 bool 在 Visual Studio 2013 中不起作用

c++ - 使用 make 编译多个 C++ 文件

c++ - 直接在 foreach 循环中强制转换

c++ - 地球opengl c++的旋转和平移

c++ - opengl 在屏幕上渲染之前旋转对象以设置其正确的面

c++ - 四元数 -> 欧拉角 -> 旋转矩阵问题 (GLM)

c++ - 如何检查一个变量是否不等于 C++ 中的多个东西?

opengl - GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 始终返回 0

c++ - QGLwidget 从 qmainwindow 弹出,即使它是 mainwindow.ui

c++ - glm::ortho() 实际上是错误的吗?