matrix - 使用 glm::perspective 关于 zFar 和 zNear 平面偏移的混淆

标签 matrix opengl graphics glm-math

我一直在使用 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/

相关文章:

java - 打印二维数组时如何插入 "-"和 "="

math - 在 Three.js 中根据局部向量定位子网格

haskell - 标量乘法与 Haskell 中的新 Matrix 类型

c++ - 开罗 + openGL + 过剩 + VS 2010 + Windows 7

c++ - 如何使用点图元将纹理映射到由参数方程渲染的球体

java - 捕获/导出 JOGL 动画到视频文件

r - 加速创建矩阵列表,每个矩阵都具有来自非常大矩阵的每一列的指定维度

java - 图形未出现在 JFrame 中(包括 SSCCE)

java - 在 OpenGL 中加载 UDEC3 或 DEC3N 数据类型

android - 如何在另一个自定义 View 中添加自定义 View ?