【发布时间】:2021-04-14 17:07:19
【问题描述】:
所以我在我的游戏引擎中实现了 Frustum Culling,但我遇到了一个奇怪的错误。我正在渲染一个被分割成块的建筑物,我只渲染截锥体中的块。我的相机从(-.033、11.65、2.2)左右开始,一切看起来都很好。我开始四处走动,没有闪烁。当我在截锥体剔除代码中设置断点时,我可以看到它确实在剔除一些网格。一切似乎都很棒。然后,当我到达建筑物的中心时,视野中的(3.9、4.17、2.23)周围的网格开始消失。另一边也是如此。我不知道为什么会存在这个错误。
我使用此处列出的提取方法Extracting View Frustum Planes (Gribb & Hartmann method) 来实现截锥体剔除。我不得不使用 glm::inverse() 而不是它建议的转置,我认为矩阵数学是针对行主矩阵给出的,所以我翻转了它。总而言之,我的平截头体平面计算看起来像
std::vector<Mesh*> render_meshes;
auto comboMatrix = proj * glm::inverse(view * model);
glm::vec4 p_planes[6];
p_planes[0] = comboMatrix[3] + comboMatrix[0]; //left
p_planes[1] = comboMatrix[3] - comboMatrix[0]; //right
p_planes[2] = comboMatrix[3] + comboMatrix[1]; //bottom
p_planes[3] = comboMatrix[3] - comboMatrix[1]; //top
p_planes[4] = comboMatrix[3] + comboMatrix[2]; //near
p_planes[5] = comboMatrix[3] - comboMatrix[2]; //far
for (int i = 0; i < 6; i++){
p_planes[i] = glm::normalize(p_planes[i]);
}
for (auto mesh : meshes) {
if (!frustum_cull(mesh, p_planes)) {
render_meshes.emplace_back(mesh);
}
}
然后我决定根据其边界框(由 ASSIMP 使用 aiProcess_GenBoundingBoxes 标志计算)来剔除每个网格,如下所示(返回 true 意味着剔除)
glm::vec3 vmin, vmax;
for (int i = 0; i < 6; i++) {
// X axis
if (p_planes[i].x > 0) {
vmin.x = m->getBBoxMin().x;
vmax.x = m->getBBoxMax().x;
}
else {
vmin.x = m->getBBoxMax().x;
vmax.x = m->getBBoxMin().x;
}
// Y axis
if (p_planes[i].y > 0) {
vmin.y = m->getBBoxMin().y;
vmax.y = m->getBBoxMax().y;
}
else {
vmin.y = m->getBBoxMax().y;
vmax.y = m->getBBoxMin().y;
}
// Z axis
if (p_planes[i].z > 0) {
vmin.z = m->getBBoxMin().z;
vmax.z = m->getBBoxMax().z;
}
else {
vmin.z = m->getBBoxMax().z;
vmax.z = m->getBBoxMin().z;
}
if (glm::dot(glm::vec3(p_planes[i]), vmin) + p_planes[i][3] > 0)
return true;
}
return false;
有什么指导吗?
更新 1: 规范化表示平面的完整 vec4 是不正确的,因为只有 vec3 表示平面的法线。此外,这种情况下不需要归一化,因为我们只关心距离的符号(而不是大小)。
同样重要的是要注意我应该使用矩阵的行而不是列。我通过替换来实现这一目标
p_planes[0] = comboMatrix[3] + comboMatrix[0];
与
p_planes[0] = glm::row(comboMatrix, 3) + glm::row(comboMatrix, 0);
在所有情况下。
【问题讨论】:
标签: c++ opengl matrix glm-math frustum