我想你可能对 glm::unProject 更感兴趣,它是 glm::project 的倒数。长话短说,glm::frustum、glm::perspective 和 glm::perspectiveFov 是构建 proj 矩阵,而类似于 vec4(0, 0, screenWidth, screenHeight) 的东西应该是一个有效的 viewport 向量。这实际上取决于您如何设置 OpenGL 相机。
一个完整的例子应该会有所帮助。
到屏幕空间并返回
导入所需的库:
#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[])
{
这是原点,在所谓的对象空间中。如果您从文件加载网格,您会在文件中找到这些 XYZ 坐标。
vec3 original(1.0f, -2.0f, 3.0f);
model 矩阵指定对象在场景中的位置。 view 矩阵指定定位对象相对于相机的相对位置。在 OpenGL 中,这些矩阵通常组合在一个称为 modelview 的矩阵中。我在这里选择了术语 model,因为这是 GLM 文档使用的,但我相信您的术语 modelview 更适合这种情况:
mat4 model = translate(mat4(1.0f), vec3(0.0f, 0.0f, -10.0f));
投影矩阵表示相机的镜头和光圈,它实际上以模拟透视的方式使场景变形,使远处的物体变得更小。您可以使用 GLM 函数,例如 frustum,其行为类似于 GL 对应项 glFrustum:
mat4 projection = frustum(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 100.0f);
视口指定绘图区域的大小和位置。对于 640x360 的窗口,您通常会使用如下内容:
vec4 viewport(0.0f, 0.0f, 640.0f, 360.0f);
project 函数具有将原点投影到屏幕上的魔力:
vec3 projected = glm::project(original, model, projection, viewport);
unProject 功能正好相反:
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;
}
从数学上讲,这就是幕后发生的事情:对象空间中的一个点原始通过将其乘以投影到屏幕空间四个矩阵模型、视图、投影和视口矩阵:
projected = Viewport * Projection * View * Model * original
而您正在寻找的相反转换本质上是:
unprojected = (Viewport * Projection * View * Model)^-1 * projected
完整代码
#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;
}