【问题标题】:OpenGL define vertex position in pixelsOpenGL以像素为单位定义顶点位置
【发布时间】:2011-10-05 04:54:01
【问题描述】:

我一直在用 OpenGL/C++ 编写一个 2D 基本游戏引擎,并在学习过程中学习一切。我仍然对定义顶点及其“位置”感到困惑。也就是我还在尝试理解OpenGL的顶点到像素的转换机制。是否可以简要解释一下,或者有人可以指出一篇文章或可以解释这一点的东西。谢谢!

【问题讨论】:

  • 仅供参考 Vertices 是 'vertex' 的复数形式。在 OpenGL 中,顶点坐标乘以一系列矩阵得到最终的屏幕 X,Y 坐标。
  • 虽然我知道你的问题的答案,但我也是 OpenGL 的新手,所以我不会发布答案,以免我说一些技术上不正确的东西。我要做的就是建议你阅读 OpenGL 的优秀作品。它会为你解决问题。如果你不怕数学,我推荐this online book
  • 这不是试图回答,但可能有助于澄清。顶点位置与像素位置没有任何关系,除非您碰巧将视口/变换设置恰到好处。顶点存在于它们自己的单位空间中。例如。如果你的纸是 10x10,那么它有多大?等等 - 10x10 英寸、厘米、英尺、英里...?
  • @Ascension:你真的是指 2D 游戏吗?或者您的意思是在 2D 屏幕上显示的 3D 游戏? OpenGL用于后者(3D->2D)。
  • 感谢大家提供的所有出色答案,在选择“正确”答案之前,我将在这里查看所有信息。虽然我认为这里没有任何 1 个正确答案,而且它们都对我有帮助,但必须选择一个,以便我将其全部审核并稍后回复,再次感谢大家帮助我!

标签: c++ opengl


【解决方案1】:

这是您最喜欢的 OpenGL 学习资源应该首先教给您的相当基本的知识。但无论如何标准的OpenGL管道如下:

  1. 顶点位置从对象空间(某个对象的局部)转换到世界空间(相对于某个全局坐标系)。此转换指定您的对象(顶点所属的)在世界中的位置

  2. 现在世界空间位置转换为相机/视图空间。这种变换由您看到场景的虚拟相机的位置和方向决定。在 OpenGL 中,这两种转换实际上合二为一,即模型视图矩阵,它直接将您的顶点从对象空间转换到视图空间。

  3. 接下来应用投影变换。模型视图变换应该只包含仿射变换(旋转、平移、缩放),而投影变换可以是透视变换,它基本上会扭曲对象以实现真实的透视图(越远的对象越小)。但是在您的 2D 视图的情况下,它可能是一个正交投影,它只不过是平移和缩放。这种变换在 OpenGL 中由投影矩阵表示。

  4. 在这 3 次(或 2 次)变换之后(然后通过 w 分量进行透视除法,这实际上实现了透视失真,如果有的话),您拥有的是标准化的设备坐标。这意味着在这些转换之后,可见对象的坐标应该在[-1,1] 范围内。超出此范围的所有内容都将被剪掉。

  5. 在最后一步中,应用视口变换并将坐标从 [-1,1] 范围变换到 [0,w]x[0,h]x[0,1] 立方体(假设调用了 glViewport(0, w, 0, h)),这是顶点在帧缓冲区,因此它的像素坐标。

使用顶点着色器时,步骤 1 到 3 实际上是在着色器中完成的,因此可以以任何您喜欢的方式完成,但通常也符合此标准模型视图 -> 投影管道。

要记住的主要事情是,在模型视图和投影变换后,坐标在[-1,1] 范围之外的每个顶点都将被剪掉。所以[-1,1]-box 在这两个转换之后确定了你的可见场景。

因此,根据您的问题,我假设您想使用以像素为单位的 2D 坐标系来进行顶点坐标和转换?在这种情况下,最好使用glOrtho(0.0, w, 0.0, h, -1.0, 1.0) 来完成,wh 是视口的尺寸。这基本上抵消了视口转换,因此将您的顶点从[0,w]x[0,h]x[-1,1]-box 转换为[-1,1]-box,然后视口转换又转换回[0,w]x[0,h]x[0,1]-box。

这些都是相当笼统的解释,没有提到实际的变换是通过矩阵向量乘法完成的,也没有谈论齐次坐标,但它们应该已经解释了要点。这个documentation of gluProject 也可能会给你一些见解,因为它实际上为单个顶点的转换管道建模。但在本文档中,他们实际上忘记在 v' = P x M x v 步骤之后提及 w 组件 (v" = v' / v'(3)) 的除法。

编辑:不要忘记查看 epatel 的答案中的first link,它更实用、更详细地解释了转换管道。

【讨论】:

    【解决方案2】:

    这叫转型。

    顶点设置在 3D 坐标中,该坐标被转换为视口坐标(进入您的窗口视图)。可以以各种方式设置此转换。作为初学者,正交变换是最容易理解的。

    http://www.songho.ca/opengl/gl_transform.html

    http://www.opengl.org/wiki/Vertex_Transformation

    http://www.falloutsoftware.com/tutorials/gl/gl5.htm

    【讨论】:

    • +1 对于第一个链接,这比我的解释更详细和准确。
    【解决方案3】:

    首先要知道 OpenGL 不使用标准像素坐标。我的意思是针对特定的分辨率,即。 800x600 你没有水平坐标在 0-799 或 1-800 范围内逐一递增。您宁愿将范围从 -1 到 1 的坐标发送到图形卡光栅化单元,然后再匹配特定的分辨率。

    我在这里省略了一个步骤 - 在所有之前你有一个 ModelViewProjection 矩阵(或在某些简单情况下的 viewProjection 矩阵),在这之前所有这些都会将你使用的坐标投射到投影平面上。默认使用的是实现一个相机,它可以转换世界的 3D 空间(View 用于将相机放置到正确的位置,Projection 用于将 3d 坐标投射到屏幕平面。在 ModelViewProjection 中,它也是将模型放置到世界中正确位置的步骤)。

    另一种情况(您可以通过这种方式使用投影矩阵来实现您想要的效果)是使用这些矩阵将一个分辨率范围转换为另一个分辨率。

    你需要一个技巧。如果你想认真一点,你应该阅读 openGL 中的 modelViewProjection 矩阵和相机。但是现在我会告诉你,使用适当的矩阵,你可以将自己的坐标系(即使用水平 0-799 和垂直 0-599 的范围)转换为标准化的 -1:1 范围。这样你就不会看到底层的 openGL api 使用他自己的 -1 to 1 系统。

    实现这一点的最简单方法是 glOrtho 函数。这是文档的链接: http://www.opengl.org/sdk/docs/man/xhtml/glOrtho.xml

    这是正确使用的示例: glMatrixMode (GL_PROJECTION) glLoadIdentity(); glOrtho (0, 800, 600, 0, 0, 1) glMatrixMode (GL_MODELVIEW)

    现在您可以使用自己的模型视图矩阵,即。用于平移(移动)对象,但不要触摸您的投影示例。此代码应在任何绘图命令之前执行。 (如果你不使用 3d 图形,实际上可以在初始化 opengl 之后)。

    这是一个工作示例:http://nehe.gamedev.net/tutorial/2d_texture_font/18002/

    只画你的数字而不是画文字。还有另一件事 - glPushMatrix 和 glPopMatrix 用于选择矩阵(在本示例中的投影矩阵) - 在将 3d 与 2d 渲染相结合之前,您不会使用它。

    您仍然可以使用模型矩阵(即用于在世界某处放置图块)和视图矩阵(例如用于缩放视图或滚动世界 - 在这种情况下,您的世界可能大于分辨率,您可以裁剪视图通过简单的翻译)

    查看我的答案后,我发现它有点混乱,但如果您感到困惑 - 只需阅读有关模型、视图和投影矩阵的内容并尝试使用 glOrtho 的示例。如果您仍然感到困惑,请随时询问。

    【讨论】:

      【解决方案4】:

      MSDN 有一个很棒的explanation。它可能在 DirectX 方面,但 OpenGL 或多或少是相同的。

      【讨论】:

      • 但它肯定会让初学者感到困惑,因为它奇怪的向量矩阵乘积与 OpenGL 的矩阵向量乘积相反。
      • 嗯,真的取决于..如果你自己实现矩阵和向量类,那么它们都是相同的;)
      【解决方案5】:

      Google 用于“opengl 渲染管道”。前五篇文章都提供了很好的阐述。

      从顶点到像素(实际上是片段,但如果您认为“像素”不会离您太远)的关键过渡处于光栅化阶段,该阶段发生在所有顶点已从世界坐标转换为屏幕坐标和剪辑。

      【讨论】:

      • @Armen:“可以简单解释一下,或者有人可以指出一篇文章或可以解释这一点的东西。”我没有这样做吗?
      • 我的评论所指的您的原始答案仅包含您现在编辑的答案的第一行。这不是一个答案。这是使用 google 的说明。
      • @Armen:仅第一段就满足了要求。其余的只是关于在我引用的文章中寻找什么的提示。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-03
      • 1970-01-01
      • 1970-01-01
      • 2016-04-15
      • 2012-11-13
      • 2020-01-14
      相关资源
      最近更新 更多