# 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.

## 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 on other sites
(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 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 coordinatesfloat 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 coordinatesfloat invW = 1.0F / clip.w;Vector3 ndc(clip.x * invW, clip.y * invW, clip.z * invW);// Calculate (x,y) viewport coordinatesglGetFloat(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 depthglGetFloat(GL_DEPTH_RANGE, buffer);float d = (buffer[1] - buffer[0]) * 0.5F;float z = (ndc.z + 1.0F) * d + buffer[0];

##### Share on other sites
Thank you both. Things are clearing up now :-)

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 14
• 12
• 29
• 11
• 44
• ### Forum Statistics

• Total Topics
634856
• Total Posts
3019661
×