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)); |
现在我想找到这个点在世界空间的实际坐标。我做了一些研究,
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矩阵的很好的候选者,而沿着
一个完整的例子应该会有帮助。
屏幕空间和背面导入所需库:
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; } |