C++/OpenGL将世界坐标转换为屏幕(2D)坐标

21

我正在使用OpenGL制作一个游戏,在游戏世界空间中有一些物体。我想要创建一个函数,可以将物体的位置(3D)转换为屏幕上的位置(2D),并返回它。

我已经知道了这些变量:物体的3D位置、投影矩阵和视图矩阵。

Matrix projectionMatrix;
Matrix viewMatrix;
Vector3 point3D;
1个回答

53

要进行此转换,您必须首先将模型空间位置转换为剪辑空间。这是通过矩阵乘法实现的。我将使用GLSL样式的代码使其更加明显:

vec4 clipSpacePos = projectionMatrix * (viewMatrix * vec4(point3D, 1.0));

请注意,在进行乘法运算之前,我是如何将您的三维向量转换为四维向量的。这是必要的,因为矩阵大小为4x4,而您无法将4x4矩阵与3D向量相乘,需要添加第四个分量。

下一步是将此位置从剪裁空间转换为归一化设备坐标空间(NDC空间)。NDC空间在所有三个轴上的范围为[-1, 1]。这是通过将前三个坐标除以第四个坐标来完成的:

vec3 ndcSpacePos = clipSpacePos.xyz / clipSpacePos.w;

显然,如果clipSpacePos.w为零,就会出现问题,所以你应该事先检查一下。如果它是零,那么这意味着物体在投影平面上;它的视图空间深度为零。这样的顶点将被OpenGL自动裁剪。

接下来要做的是将[-1,1]空间转换为窗口相关坐标。这需要使用传递给glViewport的值。前两个参数是窗口左下角的偏移量(vec2 viewOffset),后两个参数是视口区域的宽度/高度(vec2 viewSize)。给定这些值,窗口空间位置为:

vec2 windowSpacePos = ((ndcSpacePos.xy + 1.0) / 2.0) * viewSize + viewOffset;

这就是你能到达的极限。请记住:OpenGL的窗口空间相对于窗口的左下角而不是左上角。


我如何在不使用着色器程序的情况下实现这一点?我的意思是,只使用纯OpenGL函数? - mr5
在谷歌搜索了一段时间后,我找到了最好的答案,也是唯一一个提到需要除以clipSpacePos.w的答案。 - László Kustra
9
注意:如果窗口空间相对于窗口左上角,则 windowSpacePos 应为 vec2 (((ndcSpacePos.x + 1.0) / 2.0) * viewSize.x + viewOffset.x,((1.0-ndcSpacePos.y)/ 2.0)* viewSize.y + viewOffset.y) - László Kustra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接