关于opengl:如何使用glm :: project来获取世界空间中某个点的坐标?

How to use glm::project to get the coordinates of a point in world space?

我在二维空间中有一个点(1,2),我用向量表示:

1
glm::vec3 pt = glm::vec3(1, 2, 0)

(在这里,我将第三个组件设置为0-不确定是否正确?)

我有一个模型视图矩阵,可以将转换应用到以下点:

1
2
glm::mat4 ModelView = glm::mat4(1.0f);
ModelView = glm::translate(ModelView, glm::vec3(3.0f, 3.0f, 0.0f));

现在我想找到这个点在世界空间的实际坐标。我做了一些研究,glm::project()似乎可以用来做这个。它需要4个参数:

1
2
3
4
5
detail::tvec3<T> glm::gtc::matrix_transform::project(detail::tvec3<T> const & obj,
                                                     detail::tmat4x4<T> const & model,
                                                     detail::tmat4x4<T> const & proj,
                                                     detail::tvec4<U> const & viewport
)

前两个参数是我已经得到的点和模型视图矩阵。但是,第3和第4个参数(投影矩阵和视区向量)应该使用什么?如何创建/获取它们?


我认为您可能对glm::unproject更感兴趣,它与glm::project相反。长话短说,glm::frutstum、glm::perspective和glm::perspectivefov是构建proj矩阵的很好的候选者,而沿着vec4(0, 0, screenWidth, screenHeight)行的一些东西应该是有效的视区向量。这实际上取决于如何设置OpenGL相机。

一个完整的例子应该会有帮助。

屏幕空间和背面

导入所需库:

1
2
3
4
5
6
7
8
#include <iostream>
#include <glm/vec3.hpp>
#include <glm/mat4x4.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/matrix_transform.hpp>

using namespace std;
using namespace glm;

我们的主要:

1
2
int main(int argc, char *argv[])
{

这是原始点,在所谓的对象空间中。如果要从文件加载网格,可以在文件中找到这些XYZ坐标。

1
    vec3 original(1.0f, -2.0f, 3.0f);

模型矩阵指定对象在场景中的位置。视图矩阵指定定位对象相对于相机的相对位置。在OpenGL中,这些矩阵通常组合在一个称为ModelView的矩阵中。我在这里选择了术语模型,因为这是GLM文档使用的,但是您的术语模型视图更适合这种情况,我相信:

1
    mat4 model = translate(mat4(1.0f), vec3(0.0f, 0.0f, -10.0f));

投影矩阵代表相机的镜头和光圈,它实际上是以模拟透视的方式变形场景,使远处的物体变小。您可以使用一个GLM函数,如FrutStum,其行为类似于GL对应的GlutStum:

1
    mat4 projection = frustum(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 100.0f);

视区指定绘图区域的大小和位置。对于640x360窗口,您通常会使用如下内容:

1
    vec4 viewport(0.0f, 0.0f, 640.0f, 360.0f);

Project函数具有将原始点投影到屏幕的魔力:

1
    vec3 projected = glm::project(original, model, projection, viewport);

unproject函数的作用相反:

1
    vec3 unprojected = glm::unProject(projected, model, projection, viewport);

现在可以看到这两个函数是一个与另一个相反的函数:

1
2
3
4
5
6
    cout << original.x <<"" << original.y <<"" << original.z << endl;
    cout << projected.x <<"" << projected.y <<"" << projected.z << endl;
    cout << unprojected.x <<"" << unprojected.y <<"" << unprojected.z << endl;

    return 0;
}

从数学上讲,这就是在幕后发生的事情:对象空间中的原始点被投影到屏幕空间,方法是将其乘以四个矩阵模型、视图、投影和视区矩阵:

1
projected = Viewport * Projection * View * Model * original

而相反的转变,也就是你正在寻找的,本质上是:

1
unprojected = (Viewport * Projection * View * Model)^-1 * projected

全码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <glm/vec3.hpp>
#include <glm/mat4x4.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/matrix_transform.hpp>

using namespace std;
using namespace glm;

int main(int argc, char *argv[])
{
    vec3 original(1.0f, -2.0f, 3.0f);

    mat4 model = translate(mat4(1.0f), vec3(0.0f, 0.0f, -10.0f));
    mat4 projection = frustum(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 100.0f);
    vec4 viewport(0.0f, 0.0f, 640.0f, 360.0f);

    vec3 projected = glm::project(original, model, projection, viewport);
    vec3 unprojected = glm::unProject(projected, model, projection, viewport);

    cout << original.x <<"" << original.y <<"" << original.z << endl;
    cout << projected.x <<"" << projected.y <<"" << projected.z << endl;
    cout << unprojected.x <<"" << unprojected.y <<"" << unprojected.z << endl;

    return 0;
}