我正在攻读我的计算机科学学位的顶点项目,我很难弄清楚如何做标题所说的。 假设相机在原点向下看-z在gl坐标(或世界坐标中的正z) 此外,我的投影矩阵基于16x9纵横比和40度垂直fov。 zfar是1000,znear是1.
我从两个不同的角度解决了这个问题。我试图通过矩阵数学来解决它,并使用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}乘以逆投影矩阵之后,得到的矢量应该具有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}
第一个输出块中的数字是我在视图触发计算时得到的坐标。 第二个数字块是投影矩阵应用于它们之后的顶点。一旦应用了投影矩阵,结果坐标应该是所有1和-1的某种组合。但是它的版本是{0.16,0.5,0.5}。这是完全错误的。 也只是为了澄清,输出是由W划分后的坐标。 我到底错过了什么?这应该很简单,但没有任何意义。
我哪里错了?我误会了什么吗?我完全卡住了。
答案 0 :(得分:1)
在你的glm代码中,有两个主要问题:
glm假设(至少对于矩阵运算)我们正在使用列向量。这意味着,默认的操作顺序为M * t
。如果要使用t * M
形式的行向量和操作,则必须转换M才能正常工作。
-1.0的投影z坐标不位于远平面上,而是位于近平面上。此外,OpenGL预计(默认情况下)值越远越远。因此,如果你想在远平面上有一个点,那么它的z坐标必须为1.0。