如何将 2D 世界转换为屏幕坐标 OpenGL

Posted

技术标签:

【中文标题】如何将 2D 世界转换为屏幕坐标 OpenGL【英文标题】:How to transform 2D world to screen coordinates OpenGL 【发布时间】:2013-04-14 04:43:27 【问题描述】:

我目前正致力于将 OpenGL 驱动的渲染器实现到 2D 游戏引擎中。

因为 OpenGL 屏幕坐标空间是 [-1,1],我有点困惑它应该如何与通用的笛卡尔 2D 世界坐标系交互。

假设我的世界中的视口是 [-500,-500] 到 [1200, 1200],其中 [0, 0] 是世界的原点。我只需要翻译和缩小到-1和1之间的坐标吗?还是需要进行其他形式的转换?

你如何计算在你自己的坐标系中定义了位置的对象在屏幕上的绘制位置?

我会很感激有和没有 glOrtho 的解释(所以我们也可以将 Z 轴用于透视效果)。

【问题讨论】:

【参考方案1】:

首先,OpenGL使用多个坐标系,所以没有“the OpenGL坐标系”。您指的是标准化设备坐标 (NDC),其中所有三个坐标都在 [-1, 1] 范围内。不同的坐标系及其名称在“9.011 如何转换坐标?有哪些不同的坐标空间?”一节中解释了here。 1)

其次,为避免混淆,在 OpenGL 中,术语“视口”是指您要渲染到的窗口部分,它位于窗口坐标中。在您的问题中,您使用它来描述您想要渲染的世界的部分 (l,r,t,b)=(-500, -500, 1200, 1200),即世界坐标。

您问如何“计算在屏幕上绘制对象的位置”。您需要做的是定义一个从一个坐标系映射到另一个坐标系的变换(一个 4x4 矩阵)。您的 2D 世界以世界坐标给出,因此您需要定义一个将世界坐标转换为 NDC 的矩阵,即投影矩阵。然后,在您的着色器中,您只需将顶点与此投影矩阵相乘,即可获得 NDC。 glm::ortho/glOrtho 计算这样一个投影矩阵。至于透视投影,不清楚你想做什么,但你应该尝试一下glm中的perspectivelookat函数。

为了清楚起见,您可以在任何您想要的坐标系(称为世界坐标系)中定义顶点,然后简单地绘制这些顶点。您的顶点着色器的工作是应用您定义的转换。

另请注意,您指定了一个正方形,通常这不是您想要的。监视器和大多数窗口都不是正方形的,因此如果您将该正方形映射到一个典型的视口上,您会得到一个扭曲的世界视图。您需要考虑视口的纵横比(宽度:高度)。我试图解释一下here。


1) 附带说明一下,FAQ 已经很老了,指的是 OpenGL 的古老版本。如今,人们期望并鼓励程序员自己管理模型视图和投影矩阵,因为您需要在着色器中使用它们。我强烈推荐glm,它只有标题,因此很容易集成,并且语法很好,可以反映 GLSL。

【讨论】:

如果你使用正交投影矩阵,视图可以而且永远只能是二维的,因为它忽略了 Z 轴,对吗?对于我正在做的大多数事情,这很好,但我希望能够尝试使用 Z 轴在 2D 世界上创建不那么平坦的透视图。那么如何定义透视而不是正交的变换矩阵呢?哪些 GL 函数可以做到这一点? 1) 不,它不会忽略 Z 轴,它只是将具有相同 xy 坐标的所有内容投影到同一个像素上。但是您仍然可以进行深度测试。 2)glm::perspective. 你如何使用 glm::perspective?它如何与gl_ModelViewProjectionMatrix 交互? 如果你被 glm::perspective 这样的 glm 辅助函数卡住了,它是反映旧 OpenGL 行为的函数之一,在这种情况下是 glPerspective,所以谷歌搜索会得到更多的结果。与 glm::lookat -> gluLookAt、glm::ortho -> glOrtho 相同。我建议您做一些教程来帮助您入门,例如this one。它使用 OpenGL 3.3 和现代 GLSL,并解释了数学和转换。可能需要一些时间来完成,但这真的很值得。这个网站更适合更具体的问题。【参考方案2】:

在投影矩阵上使用glOrtho,然后正常绘制。对于你的例子,我猜你想要 glOrtho(0, 1000, 0, 3000, -1, 1) 这会给你一个宽 1000 个单位和高 3000 个单位的视口

【讨论】:

【参考方案3】:

将您的场景放置在您想要的任何坐标系中。我建议使用 glm (http://glm.g-truc.net/) 来初始化矩阵和执行数学运算等。所以你可能有一个场景图引擎,你可以在其中管理 2D/3D 世界中的所有对象。只需在 glm 中正确设置视图和投影。实际上,您不应该需要任何图形管道实现细节——因此您的游戏引擎中可能存在错误的设计决策。

【讨论】:

以上是关于如何将 2D 世界转换为屏幕坐标 OpenGL的主要内容,如果未能解决你的问题,请参考以下文章

关于把世界坐标投射到屏幕上转换为屏幕2D坐标

OpenGL:如何将世界坐标转换为屏幕坐标?

使用正交矩阵将 3D 坐标转换为 2D 屏幕坐标

将 2D 图像坐标转换为 z = 0 的 3D 世界坐标

将屏幕空间转换为世界空间以在 python 中创建点云

Unity中的坐标系--屏幕转世界坐标