为什么 z 坐标没有被 glm::ortho() 投影归一化?
Why z-coordinate is not normalized by glm::ortho() projection?
我试图更好地理解 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] 语句之前的负号,然后我们也会有 [-1,1] (Ortho projection in wikipedia) 范围内的 z 值。
相反,相机前面的所有点的 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 中的通用策略是,在应用 model/view 转换后,您将进入 "eye coordinate" 系统。在这个坐标系中,"camera" 位于原点,并指向 negative z 轴。所以可见的z值是负的,距离视点(原点)zNear
和zFar
的点在-zNear
和-zFar
.
现在,特别是在使用可编程流水线时,没有什么可以强制您遵循此策略。您可以以任何您想要的方式定义和应用您的转换,只要它们最终在正确的范围内生成 NDC(标准化设备坐标)。许多人仍然使用与固定管道中使用的坐标系相似的坐标系,编写 GLM 来支持这一点。
更进一步,您可能想知道为什么眼睛坐标系是这样定义的,相机指向负 z 轴。主要原因是这给了你一个右手坐标系。右手坐标系在许多应用程序以及几何中几乎是标准的。因此,大多数人更喜欢使用右手坐标系。
一旦您决定使用右手坐标系,其中的大部分内容就很容易掌握了。让 x 轴从左到右在人们想要使用的几乎任何坐标系中都是标准的。 y 轴更加模糊,在某些图形中从上到下 systems/libraries,在其他图形中从下到上。在 math/geometry 中,y 轴主要是从下到上绘制的,这是 OpenGL 使用的。
随着 x 轴从左到右,y 轴从下到上,z 轴必须指向 超出 屏幕 x/y/z 组成右手坐标系。随着正 z 轴从屏幕中出来,当您看向屏幕时,您会看到 负 z 轴的方向。
有另一种解释同一件事的方法:本机 OpenGL 坐标系 (NDC) 是左手坐标系。如果要在右手坐标系中指定坐标,则必须在管道中的某处翻转惯用手。常见的方法是翻转坐标系作为投影变换的一部分。这就是为什么在投影变换中 z 坐标与 x 和 y 坐标的处理方式不同。反转 z 坐标会将坐标系从右手系翻转到原生的左手系 OpenGL 坐标系。
我试图更好地理解 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] 语句之前的负号,然后我们也会有 [-1,1] (Ortho projection in wikipedia) 范围内的 z 值。
相反,相机前面的所有点的 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 中的通用策略是,在应用 model/view 转换后,您将进入 "eye coordinate" 系统。在这个坐标系中,"camera" 位于原点,并指向 negative z 轴。所以可见的z值是负的,距离视点(原点)zNear
和zFar
的点在-zNear
和-zFar
.
现在,特别是在使用可编程流水线时,没有什么可以强制您遵循此策略。您可以以任何您想要的方式定义和应用您的转换,只要它们最终在正确的范围内生成 NDC(标准化设备坐标)。许多人仍然使用与固定管道中使用的坐标系相似的坐标系,编写 GLM 来支持这一点。
更进一步,您可能想知道为什么眼睛坐标系是这样定义的,相机指向负 z 轴。主要原因是这给了你一个右手坐标系。右手坐标系在许多应用程序以及几何中几乎是标准的。因此,大多数人更喜欢使用右手坐标系。
一旦您决定使用右手坐标系,其中的大部分内容就很容易掌握了。让 x 轴从左到右在人们想要使用的几乎任何坐标系中都是标准的。 y 轴更加模糊,在某些图形中从上到下 systems/libraries,在其他图形中从下到上。在 math/geometry 中,y 轴主要是从下到上绘制的,这是 OpenGL 使用的。
随着 x 轴从左到右,y 轴从下到上,z 轴必须指向 超出 屏幕 x/y/z 组成右手坐标系。随着正 z 轴从屏幕中出来,当您看向屏幕时,您会看到 负 z 轴的方向。
有另一种解释同一件事的方法:本机 OpenGL 坐标系 (NDC) 是左手坐标系。如果要在右手坐标系中指定坐标,则必须在管道中的某处翻转惯用手。常见的方法是翻转坐标系作为投影变换的一部分。这就是为什么在投影变换中 z 坐标与 x 和 y 坐标的处理方式不同。反转 z 坐标会将坐标系从右手系翻转到原生的左手系 OpenGL 坐标系。