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

标签 opengl graphics glm-math

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

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

(这里我将第三个分量设置为 0 - 不确定这是否正确?)

我有一个模型 View 矩阵来对点应用翻译:

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 
)

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

最佳答案

我认为您可能对 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);

模型 矩阵指定对象在场景中的位置。 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);

视口(viewport)指定绘图区域的大小和位置。对于 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;
}

从数学上讲,这就是幕后发生的事情:对象空间中的原始点通过乘以投影到屏幕空间四个矩阵模型、 View 、投影和视口(viewport)矩阵:

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;
}

关于opengl - 如何使用 glm::project 获取世界空间中某个点的坐标?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35261192/

相关文章:

opengl - 是否可以将 OpenCV GpuMat 绑定(bind)为 OpenGL 纹理?

math - 为什么 OpenGL 支持 mipmap 但不支持积分图像?

c++ - 如何使用半空间测试确定一个点是在线段的前面还是后面?

r - 在 R 或 Matlab 中绘制这样颜色的多边形

java - 带有 Java AWT 图形的 TTF 字体

c++ - 透视投影 OPENGL 和计算着色器

c++ - GLM 在声明后定义一个 vec3

python - 了解 OpenGL 中的光与 Material 属性

python - Pygame,OpenGL : Project 3D rgb values to 2D surface

Android 图形 : Changing the alpha of just an image (not the background)