我在 2D 空间中有一个点 (1, 2),我将其表示为向量:
glm::vec3 pt = glm::vec3(1, 2, 0)
(这里我将第三个分量设置为 0 - 不确定这是否正确?)
我有一个模型视图矩阵来将平移应用于该点:
glm::mat4 ModelView = glm::mat4(1.0f);
ModelView = glm::translate(ModelView, glm::vec3(3.0f, 3.0f, 0.0f));
现在我想找到世界空间中该点的实际坐标。我做了一些研究,
glm::project()
似乎是我可以用的东西。它接受 4 个参数:
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
)
前两个参数是我已经拥有的点和模型视图矩阵。但是,我应该使用什么作为第三个和第四个参数(投影矩阵和视口向量)?我如何创建/获取它们?
我认为您可能对 glm::unProject 更感兴趣,它是 glm::project 的反面。长话短说, glm::frustum、glm::perspective 和 glm::perspectiveFov 是构建 proj 矩阵的良好候选者,而类似于
vec4(0, 0, screenWidth, screenHeight)
的东西应该是有效的 视口 向量。这实际上取决于您如何设置 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);
模型矩阵指定对象在场景中的位置。 view 矩阵指定定位对象相对于相机的相对位置。在 OpenGL 中,这些矩阵通常组合在一个称为“模型视图”的矩阵中。我在这里选择了术语 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);
函数的作用相反:
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;
}