c++ - 在世界坐标中计算 z_far 平面的顶点。

标签 c++ opengl matrix glm-math

我正在攻读计算机科学学位的顶点项目,但我无法弄清楚如何按照标题所说的去做。 假设相机位于原点,俯视 gl 坐标中的 -z(或世界坐标中的正 z) 此外,我的投影矩阵基于 16x9 纵横比和 40 度垂直视场。 zfar为1000,znear为1。

我从两个不同的角度解决了这个问题。我试图通过矩阵数学和三角函数来解决这个问题。但是,到目前为止,这两种方法都不适合我。

我的第一直觉是采用我的投影矩阵,得到该矩阵的逆矩阵,而不是乘以构成 zfar 平面的齐次坐标。 例如:

vec4(-1.0,1.0,-1.0,1.0) * inverse_projection// calculates top left vertex of z_far plane in world coords etc..

下面是演示我的意思的代码。理论上,在将 {-1,1,-1} 乘以逆投影矩阵后,所得 vector 的 z 坐标应为 1000,因为这是用于构建投影矩阵的 zfar。

glm::vec4 pp  = glm::vec4(-1, 1, -1, 1.0);


printf("zfar[0] = %.2f, %.2f, %.2f, %.2f\n", pp.x, pp.y, pp.z, pp.w);
pp = pp * inverse_projection;
printf("zfar[0] * inverse_projection = %.2f, %.2f, %.2f,  w=%.2f\n", pp.x/pp.w  ,pp.y/pp.w  ,pp.z/pp.w ,pp.w);
pp = pp * projection;
printf("zfar[0] * projection = %.2f, %.2f, %.2f,  w=%.2f\n",  pp.x/pp.w  ,pp.y/pp.w  ,pp.z/pp.w ,pp.w);

输出:

zfar[0] = -1.00, 1.00, -1.00, 1.00
zfar[0] * inverse_projection = -0.21, 0.12, -0.33,  w=1.50
zfar[0] * projection = -1.00, 1.00, -1.00,  w=1.00

但是,如您所见,它表示在世界坐标系中,z_far 为 -0.33,而它应为 -1000,这离正确还差得很远。我的猜测是我没有正确的 W 坐标,无法成功转换为世界坐标。

我还尝试通过 trg 计算 zfar。

void test_getFrustumInWorld( double height, double width, double v_fov, double z_near, double z_far, glm::mat4 projection)
{
    //height and width refer to height and width of screen
    glm::vec4 z_far_world[4];
    double z_far_height = (tan(v_fov/2)*z_far)*2;
    double aspect_ratio = height/width; //how many heights there are in one width
    double z_far_width = z_far_height * aspect_ratio;

    double zf_right = z_far_width/2.0;
    double zf_top = z_far_height/2.0;

    z_far_world[0] = glm::vec4(-zf_right, zf_top, 1000.0, 1.0);
    z_far_world[1] = glm::vec4(-zf_right,-zf_top, 1000.0, 1.0);
    z_far_world[2] = glm::vec4( zf_right,-zf_top, 1000.0, 1.0);
    z_far_world[3] = glm::vec4( zf_right, zf_top, 1000.0, 1.0);



    for(int i=0; i< 4; i++)
    {
        double w = z_far_world[i].w;
        printf("z_far_world[%d] = {%.2f, %.2f, %.2f, w=%.2f}\n",i,z_far_world[i].x/w,  z_far_world[i].y/w,  z_far_world[i].z/w,  z_far_world[i].w);

    }

    printf("\nprojected:\n");
    for(int i=0; i< 4; i++)
    {
        z_far_world[i] = z_far_world[i] * projection;
        double w = z_far_world[i].w;
        printf("z_far_world[%d] = {%.2f, %.2f, %.2f, w=%.2f}\n",i,z_far_world[i].x/w,  z_far_world[i].y/w,  z_far_world[i].z/w,  z_far_world[i].w);

    }
}

输出:

z_far_world[0] = {-1258.40, 2237.16, 1000.00, w=1.00}
z_far_world[1] = {-1258.40, -2237.16, 1000.00, w=1.00}
z_far_world[2] = {1258.40, -2237.16, 1000.00, w=1.00}
z_far_world[3] = {1258.40, 2237.16, 1000.00, w=1.00}

projected:
z_far_world[0] = {0.16, -0.50, 0.50, w=-2002.00}
z_far_world[1] = {0.16, 0.50, 0.50, w=-2002.00}
z_far_world[2] = {-0.16, 0.50, 0.50, w=-2002.00}
z_far_world[3] = {-0.16, -0.50, 0.50, w=-2002.00}

第一个输出 block 中的数字是我在 View 触发计算中到达的坐标。 第二个数字 block 是应用投影矩阵后的顶点。应用投影矩阵后,生成的坐标应该是所有 1 和 -1 的某种组合。但它变成了 {0.16, 0.5, 0.5} 之类的东西。这是完全错误的。 还要澄清一下,输出是除以 W 后的坐标。 我到底错过了什么?这应该很简单,但没有任何意义。

我哪里错了?我误会了什么吗?我完全卡住了。

最佳答案

在你的 glm 代码中,有两个主要问题:

glm 假设(至少对于矩阵运算)我们正在使用列 vector 。这意味着,默认的操作顺序是 M * t。如果您想使用 t * M 形式的行 vector 和运算,则必须转置 M 才能正常工作。

-1.0 的投影 z 坐标不位于远平面上,而是位于近平面上。此外,OpenGL 期望(默认情况下)值在距离较远时较大。因此,如果您想要远平面上的一个点,则它的 z 坐标必须为 1.0。

关于c++ - 在世界坐标中计算 z_far 平面的顶点。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43906071/

相关文章:

c++ - 如何在不使用 QTcpSockets 的情况下在 Qt 中创建插槽并将其连接到 TCP recv()?

linux - 绘制鼠标指针的 XOrg 服务器代码

image - 颜色键在图像处理中的作用是什么?

r - 将方阵分解成对

python - 如何在Pytorch中将多个矩阵对角线组合成一个大矩阵

sql - 如何在 Android 中使用列表适配器显示矩阵光标?

c++ - std::random_device 加密安全吗?

c++ - pthread_spinlock 是否会导致从用户空间切换到内核空间

c++ - Visual Studio Code - 远程调试 Bazel C++ - 无法读取文件'vscode-remote ://dev- file

c++ - OpenGL 顶点从侧面被剪切