2017-05-11 52 views
1

我正在为我的计算机科学学士学位项目工作,我很难搞清楚如何做题目所说的事情。 假设摄像机在原点向下看-Z在gl坐标(或世界坐标中的正z) 此外,我的投影矩阵基于16x9纵横比和40度垂直fov。 zfar是1000,znear是1.以世界坐标计算z_far平面的顶点。

我已经从2个不同的角度来解决这个问题。我试图通过矩阵数学计算出来,并且还使用了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} 

在输出的该第一块中的数字,是我到达视图TRIG计算的坐标。 第二个数字块是应用投影矩阵后的顶点。一旦投影矩阵被应用,结果坐标应该是所有1和-1的某种组合。但是像{0.16,0.5,0.5}这样的东西出现了。这是完全错误的。 也只是为了说明,输出是由W划分后的坐标。 我到底在想什么?这应该很简单,但没有任何意义。

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

回答

1

在您的GLM代码中,有两个主要问题:

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

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

+0

Aaah耶。我认为我是错误的,或者只是误解了当我第一次学习opengl坐标系时被告知的内容。 我发现,虽然我的主要问题,至少在trig方法中,我的FOV是度数而不是弧度。 – shalnon