【问题标题】:How to use glm::project to get the coordinates of a point in world space?如何使用 glm::project 获取世界空间中某个点的坐标?
【发布时间】:2016-02-08 01:14:36
【问题描述】:

我在 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 
)

前两个参数是我已经拥有的点和模型视图矩阵。但是,我应该为第三个和第四个参数(投影矩阵和视口矢量)使用什么?如何创建/获取它们?

【问题讨论】:

    标签: opengl graphics glm-math


    【解决方案1】:

    我想你可能对 glm::unProject 更感兴趣,它是 glm::project 的倒数。长话短说,glm::frustumglm::perspectiveglm::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;
    }
    

    【讨论】:

    • 如果我不知道顶点的位置怎么办。相反,我只想获取我在屏幕上单击的任何像素的坐标?
    • 上面的算法是一个概念证明,显示了投影和非投影。在您的情况下,您没有original,这意味着您必须根据用户输入构造projected。如果用户点击(x, y),您可以声明vec3 projected(x, y, someZ)。你如何设置someZ 取决于你想要做什么。如果您只是对沿投影线获取任何点感兴趣,可以将其设置为0;或者,如果您想重建被点击的 surface 点的实际 3D 位置,也可以将其设置为渲染像素的深度。
    猜你喜欢
    • 2014-07-05
    • 1970-01-01
    • 1970-01-01
    • 2021-06-13
    • 2021-10-22
    • 1970-01-01
    • 1970-01-01
    • 2016-02-29
    • 2020-09-12
    相关资源
    最近更新 更多