我正在攻读我的计算机科学学位项目的顶峰项目,却无法弄清楚标题的含义。
只需假设相机位于原点,即可在gl坐标中向下-z(或在世界坐标中为正z)
另外,我的投影矩阵基于16x9的纵横比和40度的垂直视野。 zfar是1000,znear是1。

我已经从2个不同的 Angular 解决了这个问题。我试图通过矩阵数学以及使用trig来弄清楚。但是,到目前为止,这两种方法都无法正常工作。

我的第一个直觉是拿我的投影矩阵,得到该矩阵的逆,而不是乘以组成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 应具有1000的z坐标,因为这是在投影矩阵的构造中使用的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}

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

我要去哪里错了?我误会了吗?我完全陷入困境。

最佳答案

在您的glm代码中,存在两个主要问题:

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

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

10-02 08:16
查看更多