为啥 z 坐标没有被 glm::ortho() 投影归一化?

Posted

技术标签:

【中文标题】为啥 z 坐标没有被 glm::ortho() 投影归一化?【英文标题】:Why z-coordinate is not normalized by glm::ortho() projection?为什么 z 坐标没有被 glm::ortho() 投影归一化? 【发布时间】:2015-08-14 17:50:45 【问题描述】:

我试图更好地理解 glm::ortho 的工作原理,源代码 (v 0.9.7) 如下所示:

template <typename T>
GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> ortho
(
    T left,
    T right,
    T bottom,
    T top,
    T zNear,
    T zFar
)

    tmat4x4<T, defaultp> Result(1);
    Result[0][0] = static_cast<T>(2) / (right - left);
    Result[1][1] = static_cast<T>(2) / (top - bottom);
    Result[2][2] = - static_cast<T>(2) / (zFar - zNear);
    Result[3][0] = - (right + left) / (right - left);
    Result[3][1] = - (top + bottom) / (top - bottom);
    Result[3][2] = - (zFar + zNear) / (zFar - zNear);
    return Result;

一切都很好并且运行良好,但有一件事让我担心。为什么生成的矩阵将坐标“x”和“y”归一化为 [-1,1](它涉及视图区域内的点),而不是“z”(深度)?

我们可以在 Result[3][2] 语句之前去掉减号,然后我们的 z 值也会在 [-1,1] 范围内 (Ortho projection in wikipedia)。

相反,相机前面的所有点的 z 值都低于 -1,但为什么呢?这是因为一些优化问题吗?或者还有什么其他理由让事情变得不那么直观?

【问题讨论】:

投影之前相机前面的所有点(眼睛空间)在 OpenGL 中传统上是 z 【参考方案1】:

它确实映射到 z 的 [-1, 1] 区间。但是,映射到此范围的值介于 -zNear-zFar 之间。

提取z的转换部分:

z --> -2 * z / (zFar - zNear) - (zFar + zNear) / (zFar - zNear) =
      (-2 * z - zFar - zNear) / (zFar - zNear)

并插入-zNear-zFar

-zNear --> (2 * zNear - zFar - zNear) / (zFar - zNear) =
           (zNear - zFar) / (zFar - zNear) =
           -1
-zFar --> (2 * zFar - zFar - zNear) / (zFar - zNear) =
          (zFar - zNear) / (zFar - zNear) =
          1

为什么我们要映射负 z 值? OpenGL 中的常见策略是,在应用模型/视图转换后,您处于“眼睛坐标”系统中。在这个坐标系中,“相机”位于原点,并指向 z 轴。所以可见的z值为负,距离眼点(原点)zNearzFar的点在-zNear-zFar

现在,特别是在使用可编程流水线时,没有什么会迫使您遵守此政策。您可以以任何您想要的方式定义和应用您的转换,只要它们最终产生正确范围内的 NDC(标准化设备坐标)。许多人仍然使用与固定管道中使用的坐标系相似的坐标系,而 GLM 就是为了支持这一点而编写的。

再进一步,您可能想知道为什么眼睛坐标系是这样定义的,相机指向负 z 轴。主要原因是这为您提供了右手坐标系。右手坐标系在许多应用以及几何中都是非常标准的。因此,大多数人更喜欢使用右手坐标系。

一旦您决定使用右手坐标系,这其中的大部分内容几乎就位。在人们想要使用的几乎任何坐标系中,让 x 轴从左到右是标准的。 y 轴更加模糊,在某些图形系统/库中从上到下,在其他图形系统/库中从下到上。在数学/几何中,y 轴主要是从下到上绘制的,这是 OpenGL 使用的。

x 轴从左到右,y 轴从下到上,z 轴必须指向 屏幕外,x/y/z 才能形成右手坐标系。随着正 z 轴从屏幕中出来,当您看向屏幕时,您会朝 z 轴的方向看。

还有另一种解释同一事物的方法:原生 OpenGL 坐标系 (NDC) 是左撇子。如果要在右手坐标系中指定坐标,则必须在管道中的某处翻转手性。常用的方法是翻转坐标系作为投影变换的一部分。这就是为什么 z 坐标与投影变换中的 x 和 y 坐标不同的原因。反转 z 坐标会将坐标系从右手坐标系翻转到原生左手 OpenGL 坐标系。

【讨论】:

+1:啊哈,谢谢。我不太确定 GLM 是否使用旧的固定功能约定。因为它是为基于着色器的 GL 构建的,所以我认为它可能适用于产生眼睛空间的矩阵。

以上是关于为啥 z 坐标没有被 glm::ortho() 投影归一化?的主要内容,如果未能解决你的问题,请参考以下文章

Opengl - GLM :: Ortho + GLM_COORDINATE_SYSTEM =很奇怪?

初识OpenGL (-)坐标空间

初识OpenGL (-)坐标空间

Model, View(Camera), Perspective

了解 glm::ortho() 的参数如何影响投影后的顶点位置

OpenGL中的正交投影问题