正在计算世界坐标中 z_far 平面的顶点。

Calculating vertices of z_far plane in world coordinates.

我正在攻读计算机科学学位的顶点项目,但我无法弄清楚如何按照标题所说的去做。 假设相机位于原点,俯视 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} 乘以逆投影矩阵后,所得向量的 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}

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

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

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

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

-1.0 的投影 z 坐标不在远平面上,而是在近平面上。此外,OpenGL 期望(默认情况下)值在距离较远时较大。所以如果你想要远平面上的一个点,那么它必须有一个 1.0 的 z 坐标。