1
votes

Im working on my capstone project for a computer science degree and im having trouble figuring out how to do what the title says. Just assume the camera is at the origin looking down -z in gl coordinates(or positive z in world coordinates) Also, my projection matrix is based on a 16x9 aspect ratio with a 40 degree vertical fov. The zfar is 1000, and znear is 1.

I have approached this problem from 2 different angles. I tried to figure it out via matrix math, and also using trig. However neither approach is working correctly for me so far.

My first instinct, was to take my projection matrix, get the inverse of that matrix, than multiply the homogeneous coordinates that make up the zfar plane. for example:

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

Below, is the code that demonstrates what i mean. Theoretically, after multiplying the {-1,1,-1} by the inverse projection matrix the resulting vector should have a z coordinate of 1000, since that is the zfar used in the construction of the projection matrix.

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);

Output:

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

But, As you can see, it says that in world coordinates, z_far is at -0.33, when it should be at -1000 Its not even close to being right. My guess is that i dont have the W coordinate correct for it to successfully translate into world coordinates.

I also tried calculating the zfar via trg.

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);

    }
}

Output:

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}

The numbers in that first block of output, are the coordinates i arrived at view trig calculations. The second block of numbers is the vertices after the projection matrix was applied to them. Once the projection matrix is applied, the resulting coordinate should some combination of all 1 and -1. but instaed its something like {0.16, 0.5, 0.5}. Which is totally wrong. Also just to clarify, the output is the coords after a division by W. What the hell am i missing? this should have been simple, but nothing is making sense.

Where am i going wrong? Am i misunderstanding something? Im totally stuck.

1

1 Answers

1
votes

In your glm code, there are two major problems:

glm assumes (at least for matrix operations) that we are working with column vectors. This means, that the default order of operations is M * t. If you want to use row vectors and operations of the form t * M , then M has to be transposed to work correctly.

A projected z-coordinate of -1.0 is not located on the far plane but on the near plane. Also OpenGL expects (by default) values to be larger when they are further away. So if you want a point on the far plane, then it has to have a z coordinate of 1.0.