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.