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

Dan*_*nny 17 c++ opengl matrix

我在OpenGL中制作游戏,我在世界空间中有一些对象.我想创建一个函数,我可以在其中获取对象的位置(3D)并将其转换为屏幕的位置(2D)并返回它.

我知道以下变量中对象的3D位置,投影矩阵和视图矩阵:

Matrix projectionMatrix;
Matrix viewMatrix;
Vector3 point3D;
Run Code Online (Sandbox Code Playgroud)

Nic*_*las 36

要进行此变换,必须首先获取模型空间位置并将其转换为剪辑空间.这是通过矩阵乘法完成的.我将使用GLSL风格的代码来明确我正在做的事情:

vec4 clipSpacePos = projectionMatrix * (viewMatrix * vec4(point3D, 1.0));
Run Code Online (Sandbox Code Playgroud)

注意我如何在乘法之前将3D矢量转换为4D矢量.这是必要的,因为矩阵是4x4,并且您不能将4x4矩阵与3D矢量相乘.你需要第四个组件.

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

vec3 ndcSpacePos = clipSpacePos.xyz / clipSpacePos.w;
Run Code Online (Sandbox Code Playgroud)

显然,如果clipSpacePos.w为零,则表示您有问题,所以您应该事先检查一下.如果它为零,则表示该对象位于投影平面内; 它的视空间深度为零.这样的顶点会被OpenGL自动剪裁.

下一步是从这个[-1,1]空间转换为窗口相对坐标.这需要使用您传递给的值glViewport.前两个参数是窗口左下角的偏移量(vec2 viewOffset),后两个参数是视口区域(vec2 viewSize)的宽度/高度.鉴于这些,窗口空间位置是:

vec2 windowSpacePos = ((ndcSpacePos.xy + 1.0) / 2.0) * viewSize + viewOffset;
Run Code Online (Sandbox Code Playgroud)

这就是你去的地方.请记住:OpenGL的窗口空间相对于窗口的左下角而不是左上角.

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