我在 CPU 上实现了 Clip-Space Frustum Culling。在一个简单的简化案例中,我只是创建了一个基于 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 * Position)
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,并且应该在视锥体之外。
我已经仔细检查了我的矩阵。我还在顶点着色器中做了一个变换反馈,可以肯定的是,我在 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 之间的线...
[编辑]现在我通过计算相机平截头体法线和黑森法线方程来实现世界空间剔除。这适用于正确识别。遗憾的是,我确实需要在剪辑空间中进行正确的计算,因为我将使用这些点进行其他计算。有人有什么想法吗?
这是我的计算代码:
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;