Jump to content
  • Advertisement
Sign in to follow this  
HolyFish

OpenGL Unexpected results when calculating with Projection Matrix

This topic is 4871 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I'm doing my first steps in OpenGL and I'm trying to understand the way the ModelView and Projection matrices work. I, more or less, know what their use is but I'm getting unexpected results when doing some test-calculations. As I see it: The Projection Matrix is a simple matrix that defines the Viewing-frustum of your "camera" and holds the information about how OpenGL should transform the 3D-vertices in your scene to equivalent 2D-coordinates on your screen. So far, so good, but now I wanted to test this myself. If I multiply a random vertex with the projection matrix I should get the projected value (as I would see it on screen) right? Here is my code:
Vector3* v = new Vector3(16.0f, 7.0f,10.0f);
		
float buffer[16];
glGetFloat(GL_PROJECTION_MATRIX, buffer);
		
Vector3* proj = new Vector3(v.x*buffer[0] + v.y*buffer[1] + v.z*buffer[2],
				v.x*buffer[3] + v.y*buffer[4] + v.z*buffer[5],
				v.x*buffer[6] + v.y*buffer[7] + v.z*buffer[8]);
The camera is in position (0, 0, 6) and the result I get here is: (20.784609, 17.320507, 0.0). The Z-coordinate is 0, that seems right, but in what coordinate-system are the X and Y values? Am I making a mistake? Thank you.

Share this post


Link to post
Share on other sites
Advertisement
(1) The matrices in OpenGL are given in "column major order", what means that the indices are not as you assume (you assume "row major order"). So the first correction would be:

Vector3* proj = new Vector3(v.x*buffer[0] + v.y*buffer[4] + v.z*buffer[8],
v.x*buffer[1] + v.y*buffer[5] + v.z*buffer[9],
v.x*buffer[2] + v.y*buffer[6] + v.z*buffer[10]);


(Notice that this "major order" thingy comes from the fact that the 2D matrix is accessed by a 1D indexing.)

(2) You use a vertex, and a vertex is a "position vector". But you use it as a "direction vector". Look at the homogeneous co-ordinate w for the difference: w is 1 for a (normalized) position vector, but 0 for a direction vector! So the second correction would be:

Vector3* proj = new Vector3(v.x*buffer[0] + v.y*buffer[4] + v.z*buffer[8] + buffer[12],
v.x*buffer[1] + v.y*buffer[5] + v.z*buffer[9] + buffer[13],
v.x*buffer[2] + v.y*buffer[6] + v.z*buffer[10] + buffer[14]);



(3) The projection matrix is special in that it does _not_ provide an affine transformation. So you have to take also the lowest row into account, since it stores the perspective stuff if you do a perspective projection (as far as I remember; maybe I'm wrong here).

Vector3* proj = new Vector3(v.x*buffer[0] + v.y*buffer[4] + v.z*buffer[8] + buffer[12],
v.x*buffer[1] + v.y*buffer[5] + v.z*buffer[9] + buffer[13],
v.x*buffer[2] + v.y*buffer[6] + v.z*buffer[10] + buffer[14]);
float proj_w = v.x*buffer[3] + v.y*buffer[7] + v.z*buffer[11] + v.z*buffer[15];

proj /= proj_w; // normalize



[Edited by - haegarr on November 23, 2005 4:39:49 AM]

Share this post


Link to post
Share on other sites
Vertices go through multiple transformations to get from camera space to the screen. The following code mirrors what OpenGL does. First, the projection matrix transforms a camera-space vertex into homogeneous clip-space coordinates (hence the 4-dimensional vector 'clip'). Then, the clip-space position is divided by its w-coordinate to obtain 3D normalized device coordinates. In NDC, the view frustum has been mapped to the unit cube extending from -1 to 1 in each direction. Finally, the viewport transformation is applied to map positions from NDC to the viewport. The z-coordinate in viewport space is the depth that's written to the depth buffer.


Vector3 v(16.0F, 7.0F, 10.0F);

// Calculate clip-space coordinates

float buffer[16];
glGetFloat(GL_PROJECTION_MATRIX, buffer);

Vector4 clip(buffer[0]*v.x + buffer[4]*v.y + buffer[8]*v.z + buffer[12],
buffer[1]*v.x + buffer[5]*v.y + buffer[9]*v.z + buffer[13],
buffer[2]*v.x + buffer[6]*v.y + buffer[10]*v.z + buffer[14],
buffer[3]*v.x + buffer[7]*v.y + buffer[11]*v.z + buffer[15]);

// Calculate normalized device coordinates

float invW = 1.0F / clip.w;
Vector3 ndc(clip.x * invW, clip.y * invW, clip.z * invW);

// Calculate (x,y) viewport coordinates

glGetFloat(GL_VIEWPORT, buffer);
float w = buffer[2] * 0.5F;
float h = buffer[3] * 0.5F;

float x = (ndc.x + 1.0F) * w + buffer[0];
float y = (ndc.y + 1.0F) * h + buffer[1];

// Calculate z depth

glGetFloat(GL_DEPTH_RANGE, buffer);
float d = (buffer[1] - buffer[0]) * 0.5F;

float z = (ndc.z + 1.0F) * d + buffer[0];


Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!