2011-12-13 333 views
11

我在OpenGL中制作了一个游戏,其中我在世界空间中有几个物体。我想要制作一个功能,让我可以接收对象的位置(3D)并将其转换到屏幕的位置(2D)并返回。C++/OpenGL将世界坐标转换为屏幕(2D)坐标

我知道下面的可变因素的对象,保护矩阵和视图矩阵的3D位置:

Matrix projectionMatrix; 
Matrix viewMatrix; 
Vector3 point3D; 

回答

29

要做到这一点改变,你必须首先把你的模型空间中的位置和改造他们夹-空间。这是通过矩阵乘法完成的。我将使用GLSL风格的代码,使我在做很明显的:

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

通知我如何转换您的3D载体引入4D向量乘法之前。这是必要的,因为矩阵是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的窗口空间相对于窗口的左下角的而不是左上角的

+0

如何在没有使用着色器程序的情况下实现这一目标?我的意思是,只是普通的OpenGL函数? – mr5

+0

我经过一段时间谷歌搜索后发现的最佳答案,也是我发现的唯一一个提到不得不由clipSpacePos.w进行分割的人。 –

+2

注意:如果窗口空间相对于窗口的左上角,那么'windowSpacePos'应该是 'vec2(((ndcSpacePos.x + 1.0)/ 2.0)* viewSize.x + viewOffset.x,( (1.0 - ndcSpacePos.y)/ 2.0)* viewSize.y + viewOffset.y)' –

相关问题