我一直在使用 glm 来帮助构建一个用于自学的软件光栅器。在我的相机类中,我使用 glm::lookat() 创建 View 矩阵,并使用 glm::perspective() 创建透视矩阵。
我似乎得到了我对左、右上和下剪裁平面的期望。然而,我似乎要么为我的近/远平面做错了什么,要么我的理解有错误。我已经到了我的“google-fu”让我失望的地步。
假设我正确地从 glm::perspective 矩阵中提取裁剪平面,并使用通用平面方程:
aX+bY+cZ+d = 0
我的 zNear 和 zFar 平面出现奇怪的 d 或 “偏移” 值。 据我了解,d 值是我将沿法线向量移动/平移平面上的点 P0 的值。
它们分别是 0.200200200 和 -0.200200200。然而,我的法线沿着 z 轴正确定向在 +1.0f 和 -1.f 处,正如垂直于我的 z 基向量的平面所预期的那样。
因此,当针对这些平面测试诸如 (0, 0, -5) 世界空间之类的点时,它会被我的 View 矩阵转换为:
(0, 0, 5.81181192)
因此在剪辑链中针对这些平面进行测试,示例顶点将被剔除。
这是建立相关矩阵的相机类的开始:
static constexpr glm::vec3 UPvec(0.f, 1.f, 0.f);
static constexpr auto zFar = 100.f;
static constexpr auto zNear = 0.1f;
Camera::Camera(glm::vec3 eye, glm::vec3 center, float fovY, float w, float h) :
viewMatrix{ glm::lookAt(eye, center, UPvec) },
perspectiveMatrix{ glm::perspective(glm::radians<float>(fovY), w/h, zNear, zFar) },
frustumLeftPlane {setPlane(0, 1)},
frustumRighPlane {setPlane(0, 0)},
frustumBottomPlane {setPlane(1, 1)},
frustumTopPlane {setPlane(1, 0)},
frstumNearPlane {setPlane(2, 0)},
frustumFarPlane {setPlane(2, 1)},
视锥体对象基于以下结构:
struct Plane
{
glm::vec4 normal;
float offset;
};
我从透视矩阵中提取了 6 个裁剪平面,如下所示:
Plane Camera::setPlane(const int& row, const bool& sign)
{
float temp[4]{};
Plane plane{};
if (sign == 0)
{
for (int i = 0; i < 4; ++i)
{
temp[i] = perspectiveMatrix[i][3] + perspectiveMatrix[i][row];
}
}
else
{
for (int i = 0; i < 4; ++i)
{
temp[i] = perspectiveMatrix[i][3] - perspectiveMatrix[i][row];
}
}
plane.normal.x = temp[0];
plane.normal.y = temp[1];
plane.normal.z = temp[2];
plane.normal.w = 0.f;
plane.offset = temp[3];
plane.normal = glm::normalize(plane.normal);
return plane;
}
任何帮助将不胜感激,因为现在我不知所措。
非常感谢。
最佳答案
平面方程的 d 参数描述平面沿平面法线偏离原点的程度。这还考虑了法线的长度。
不能只标准化法线而不调整 d 参数,因为标准化会改变法线的长度。如果您想标准化平面方程,那么您还必须将除法步骤应用于 d 坐标:
float normalLength = sqrt(temp[0] * temp[0] + temp[1] * temp[1] + temp[2] * temp[2]);
plane.normal.x = temp[0] / normalLength;
plane.normal.y = temp[1] / normalLength;
plane.normal.z = temp[2] / normalLength;
plane.normal.w = 0.f;
plane.offset = temp[3] / normalLength;
旁注 1:通常,人们会将平面方程的偏移量存储在 vec4 的 w 坐标中,而不是存储在单独的变量中。原因是您使用它执行的典型操作是点到平面距离检查,例如 dist = n * x - d
(对于给定点 x,法线 n,偏移 d,* 是点积),然后可以写为 dist = [n, d] * [x, -1]
。
旁注 2:大多数软件和硬件光栅化器都会在投影步骤之后执行剪切,因为它更便宜且更容易实现。
关于matrix - 使用 glm::perspective 关于 zFar 和 zNear 平面偏移的混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69244161/