C++ OpenGL以像素为单位定义顶点位置

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7377912/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:51:24  来源:igfitidea点击:

OpenGL define vertex position in pixels

c++opengl

提问by Christian Rau

I've been writing a 2D basic game engine in OpenGL/C++ and learning everything as I go along. I'm still rather confused about defining vertices and their "position". That is, I'm still trying to understand the vertex-to-pixels conversion mechanism of OpenGL. Can it be explained briefly or can someone point to an article or something that'll explain this. Thanks!

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

回答by Christian Rau

This is rather basic knowledge that your favourite OpenGL learning resource should teach you as one of the first things. But anyway the standard OpenGL pipeline is as follows:

这是你最喜欢的 OpenGL 学习资源应该教给你的第一件事的基本知识。但无论如何,标准的 OpenGL 管道如下:

  1. The vertex position is transformed from object-space (local to some object) into world-space (in respect to some global coordinate system). This transformation specifies where your object (to which the vertices belong) is located in the world

  2. Now the world-space position is transformed into camera/view-space. This transformation is determined by the position and orientation of the virtual camera by which you see the scene. In OpenGL these two transformations are actually combined into one, the modelview matrix, which directly transforms your vertices from object-space to view-space.

  3. Next the projection transformation is applied. Whereas the modelview transformation should consist only of affine transformations (rotation, translation, scaling), the projection transformation can be a perspective one, which basically distorts the objects to realize a real perspective view (with farther away objects being smaller). But in your case of a 2D view it will probably be an orthographic projection, that does nothing more than a translation and scaling. This transformation is represented in OpenGL by the projection matrix.

  4. After these 3 (or 2) transformations (and then following perspective division by the w component, which actually realizes the perspective distortion, if any) what you have are normalized device coordinates. This means after these transformations the coordinates of the visible objects should be in the range [-1,1]. Everything outside this range is clipped away.

  5. In a final step the viewport transformation is applied and the coordinates are transformed from the [-1,1]range into the [0,w]x[0,h]x[0,1]cube (assuming a glViewport(0, w, 0, h)call), which are the vertex' final positions in the framebuffer and therefore its pixel coordinates.

  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)调用),这是顶点在帧缓冲区中的最终位置,因此是它的像素坐标。

When using a vertex shader, steps 1 to 3 are actually done in the shader and can therefore be done in any way you like, but usually one conforms to this standard modelview -> projection pipeline, too.

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

The main thing to keep in mind is, that after the modelview and projection transforms every vertex with coordinates outside the [-1,1]range will be clipped away. So the [-1,1]-box determines your visible scene after these two transformations.

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

So from your question I assume you want to use a 2D coordinate system with units of pixels for your vertex coordinates and transformations? In this case this is best done by using glOrtho(0.0, w, 0.0, h, -1.0, 1.0)with wand hbeing the dimensions of your viewport. This basically counters the viewport transformation and therefore transforms your vertices from the [0,w]x[0,h]x[-1,1]-box into the [-1,1]-box, which the viewport transformation then transforms back to the [0,w]x[0,h]x[0,1]-box.

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

These have been quite general explanations without mentioning that the actual transformations are done by matrix-vector-multiplications and without talking about homogenous coordinates, but they should have explained the essentials. This documentation of gluProjectmight also give you some insight, as it actually models the transformation pipeline for a single vertex. But in this documentation they actually forgot to mention the division by the w component (v" = v' / v'(3)) after the v' = P x M x vstep.

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

EDIT:Don't forget to look at the first linkin epatel's answer, which explains the transformation pipeline a bit more practical and detailed.

编辑:不要忘记查看epatel 答案中的第一个链接,它更实用和详细地解释了转换管道。

回答by epatel

It is called transformation.

这叫做转化。

Vertices are set in 3D coordinates which is transformed into a viewport coordinates (into your window view). This transformation can be set in various ways. Orthogonal transformation can be easiest to understand as a starter.

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

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

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

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

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

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

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

回答by Ernest Staszuk

Firstly be aware that OpenGL not uses standard pixel coordinates. I mean by that for particular resolution, ie. 800x600 you dont have horizontal coordinates in range 0-799 or 1-800 stepped by one. You rather have coordinates ranged from -1 to 1 later send to graphic card rasterizing unit and after that matched to particular resolution.

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

I ommited one step here - before all that you have an ModelViewProjection matrix (or viewProjection matrix in some simple cases) which before all that will cast coordinates you use to an projection plane. Default use of that is to implement a camera which converts 3D space of world (View for placing an camera into right position and Projection for casting 3d coordinates into screen plane. In ModelViewProjection it's also step of placing a model into right place in world).

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

Another case (and you can use Projection matrix this way to achieve what you want) is to use these matrixes to convert one range of resolutions to another.

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

And there's a trick you will need. You should read about modelViewProjection matrix and camera in openGL if you want to go serious. But for now I will tell you that with proper matrix you can just cast your own coordinate system (and ie. use ranges 0-799 horizontaly and 0-599 verticaly) to standarized -1:1 range. That way you will not see that underlying openGL api uses his own -1 to 1 system.

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

The easiest way to achieve this is glOrtho function. Here's the link to documentation: http://www.opengl.org/sdk/docs/man/xhtml/glOrtho.xml

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

This is example of proper usage: glMatrixMode (GL_PROJECTION) glLoadIdentity (); glOrtho (0, 800, 600, 0, 0, 1) glMatrixMode (GL_MODELVIEW)

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

Now you can use own modelView matrix ie. for translation (moving) objects but don't touch your projection example. This code should be executed before any drawing commands. (Can be after initializing opengl in fact if you wont use 3d graphics).

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

And here's working example: http://nehe.gamedev.net/tutorial/2d_texture_font/18002/

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

Just draw your figures instead of drawing text. And there is another thing - glPushMatrix and glPopMatrix for choosen matrix (in this example projection matrix) - you wont use that until you combining 3d with 2d rendering.

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

And you can still use model matrix (ie. for placing tiles somewhere in world) and view matrix (in example for zooming view, or scrolling through world - in this case your world can be larger than resolution and you could crop view by simple translations)

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

After looking at my answer I see it's a little chaotic but If you confused - just read about Model, View, and Projection matixes and try example with glOrtho. If you're still confused feel free to ask.

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

回答by Goz

MSDN has a great explanation. It may be in terms of DirectX but OpenGL is more-or-less the same.

MSDN 有很好的解释。它可能是在 DirectX 方面,但 OpenGL 或多或少是相同的。

回答by Marcelo Cantos

Google for "opengl rendering pipeline". The first five articles all provide good expositions.

谷歌搜索“opengl 渲染管道”。前五篇文章都提供了很好的阐述。

The key transition from vertices to pixels (actually, fragments, but you won't be too far off if you think "pixels") is in the rasterization stage, which occurs after all vertices have been transformed from world-coordinates to screen coordinates and clipped.

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