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

Posted

技术标签:

【中文标题】了解 glm::ortho() 的参数如何影响投影后的顶点位置【英文标题】:Understanding how glm::ortho()'s arguments affect vertex location after projection 【发布时间】:2017-02-21 07:10:59 【问题描述】:

在搜索了很多页面、glm 文档、教程等之后,我仍然对某些事情感到困惑。

我试图理解为什么我需要应用以下转换来获得我的 800x600(全屏正方形,对于这个最小示例,假设用户的屏幕是 800x600)图像来绘制所有内容。假设我只画逆时针三角形。在我的代码中一切都很好,但我必须执行以下操作:

// Vertex data (x/y/z), using EBOs
  0.0f, 600.0f, 1.0f,
800.0f,   0.0f, 1.0f,
  0.0f,   0.0f, 1.0f,
800.0f, 600.0f, 1.0f

// Later on...
glm::mat4 m, v, p;
m = scale(m, glm::vec3(-1.0, 1.0, 1.0));
v = rotate(v, glm::radians(180.0f), glm::vec3(0.0f, 1.0f, 0.0f));
p = glm::ortho(0.0f, 800.0f, 600.0f, 0.0f, 0.5f, 1.5f);

(请注意,由于我使用了变量名称mvp,并不意味着它们实际上是该名称的正确转换,以上只是我想要的)

我对以下内容感到困惑:

正交边界在哪里?我假设它指向负 z 轴,但是左/右边界在哪里?这是否意味着 x 轴上的 [-400, 400] 映射到 [-1.0, 1.0] NDC,或者 [0, 800] 映射到它? (我假设这里的任何答案都适用于 y 轴)。然后文档只是说Creates a matrix for an orthographic parallel viewing volume.

如果您翻转以下第三个和第四个参数会发生什么(我问是因为我看到有人这样做,但我不知道这是一个错误/错字还是侥幸...无论如何都可以正常工作):

这里是第三和第四个参数:

                              _____________
                             |  These two  |
p1 = glm::ortho(0.0f, 800.0f, 600.0f, 0.0f, 0.5f, 1.5f);
p2 = glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.5f, 1.5f);
现在我假设第三个问题将通过上述两个问题得到解答,但我试图弄清楚这是否是我的第一段代码需要我翻转 x 轴上的所有内容才能工作的原因......我会承认我只是在搞砸它,它碰巧奏效了。我想我需要一个 180 度的旋转来转动我的飞机,所以它在 -z 侧......所以我只需要弄清楚 -1.0、1.0、1.0 的缩放比例。

这个例子中提供的代码(减去变量名)是我唯一使用的东西,而且渲染效果很好……只是我不知道为什么它会起作用。

编辑:试图从here 中理解它,将网站上的图像和描述用作单个参考示例。我可能没抓住重点。

EDIT2:作为一个随机问题,由于我总是在 z = 1.0 处绘制我的平面,我是否应该出于任何原因将我的正交投影近/远平面限制为尽可能接近 1.0(例如:0.99、1.01)?假设没有其他内容被绘制或将被绘制。

【问题讨论】:

【参考方案1】:

您可以假设正交投影中的可见区域是视图空间中给定的立方体。然后将该立方体映射到 NDC 坐标中的 [-1,1] 立方体,这样立方体内部的所有内容都是可见的,而外部的所有内容都将被剪掉。一般情况下,观察者沿Z轴负方向看,+x为右,+Y为上。

正交边界如何映射到 NDC 空间?

立方体的边长由传递给glOrtho的参数给出。在第一个例子中,left 和 right 的参数是 [0, 800],因此沿 X 轴从 0 到 800 的空间映射到沿 NDC X 轴的 [-1, 1]。类似的逻辑发生在其他两个轴上(沿 y 的顶部/底部,沿 -z 的近/远)。

交换顶部和底部参数会发生什么?

互换,例如顶部和底部,相当于沿此轴镜像场景。如果您查看orthographic matrix 的第二个对角线元素,它被定义为2 / (top - bottom)。通过交换顶部和底部,只有这个元素的符号会改变。这同样适用于左与右或近与远的交换。有时,当屏幕空间原点应该是左下角而不是左上角时,会使用此选项。

为什么要将四边形旋转 180° 并进行镜像?

如上所述,近值和远值沿 Z 轴。沿 -Z 的 [0.5, 1.5] 值在世界空间坐标中表示 [-0.5, -1.5]。由于平面定义为 z=1.0,因此它位于可见区域之外。通过将其围绕原点旋转 180 度,将其移动到 z=-1.0,但现在您是从后面看它,这意味着背面剔除罢工。通过沿 X 镜像,绕线顺序发生变化,因此背面和正面也发生了变化。

由于我总是在 Z = 1.0 处绘制平面,我是否应该将我的正交投影近/远平面限制为尽可能接近 1.0?

只要不画别的,基本可以随便选。当绘制多个对象时,near 和 far 之间的范围定义了存储深度差异的精确程度。

【讨论】:

以上是关于了解 glm::ortho() 的参数如何影响投影后的顶点位置的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL中的正交投影问题

初识OpenGL (-)坐标空间

初识OpenGL (-)坐标空间

Model, View(Camera), Perspective

使用 GLM 正交投影矩阵将三角形顶点放在错误的位置

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