OpenGL projection matrix bug?

Gurus, Hi:

I have a snippet of codes below. My intentions is to use projection matrix to implement transform(-8,-6,-84) and then use viewing volume for final display. However, it just does not work(looks like it is opengl bug:) read my reasoning below.

glMatrixMode(GL_MODELVIEW); glLoadIdentity();
glMatrixMode(GL_PROJECTION); glLoadIdentity();
gluLookAt(8,6,84, 8,6,0, 0,1,0);
glFrustum(-11,11,-11,11,30,200);

glPolygonMode( GL_FRONT_AND_BACK , GL_LINE );
glBegin( GL_POLYGON );
glVertex3f(0,0,54);
glVertex3f(16,0,54);
glVertex3f(16,10,54);
glVertex3f(8,16,54);
glVertex3f(0,10,54);
glEnd();

If I switch the order of gluLookAt and glFrustum to be

glFrustum(-11,11,-11,11,30,200);
gluLookAt(8,6,84, 8,6,0, 0,1,0);

then everything is fine.

In my understanding, if I want to transform a sphere at origin to (x,y)=(1,1) position. We need to specify the matrix
glRotatef(45, 0,1,0);
glTranslatef(square_root(2), 0, 0);

if we specify
glTranslatef(square_root(2), 0, 0);
glRotatef(45, 0,1,0);
the sphere will be at (square_root(2), 0).

Furthermore, if I move the translation matrix to model view as below

glMatrixMode(GL_MODELVIEW);glLoadIdentity();
glTranslatef(-8,-6,-84);
glMatrixMode(GL_PROJECTION);glLoadIdentity();
glFrustum(-11,11,-11,11,30,200);

The result will be okay too.

Anybody know why? ( I can provide you tester program if needed)

Originally posted by /* tSb */:
Gurus, Hi:

I have a snippet of codes below. My intentions is to use projection matrix to implement transform(-8,-6,-84).
and then use viewing volume for final display. However, it just does not work(looks like it is opengl bug:) read my reasoning below.

that might be a problem. Try using the projection matrix to set the frustum and then the modelview matrix to position the camera.

glMatrixMode(GL_MODELVIEW); glLoadIdentity();
glMatrixMode(GL_PROJECTION); glLoadIdentity();
gluLookAt(8,6,84, 8,6,0, 0,1,0);
glFrustum(-11,11,-11,11,30,200);

glPolygonMode( GL_FRONT_AND_BACK , GL_LINE );
glBegin( GL_POLYGON );
glVertex3f(0,0,54);
glVertex3f(16,0,54);
glVertex3f(16,10,54);
glVertex3f(8,16,54);
glVertex3f(0,10,54);
glEnd();

If I switch the order of gluLookAt and glFrustum to be

glFrustum(-11,11,-11,11,30,200);
gluLookAt(8,6,84, 8,6,0, 0,1,0);

then everything is fine.

yup, that’s because that is the right order.

In my understanding, if I want to transform a sphere at origin to (x,y)=(1,1) position. We need to specify the matrix
glRotatef(45, 0,1,0);
glTranslatef(square_root(2), 0, 0);

if we specify
glTranslatef(square_root(2), 0, 0);
glRotatef(45, 0,1,0);
the sphere will be at (square_root(2), 0).

correct. The first method is wrong. Transforms happen in reverse order.

Furthermore, if I move the translation matrix to model view as below

glMatrixMode(GL_MODELVIEW);glLoadIdentity();
glTranslatef(-8,-6,-84);
glMatrixMode(GL_PROJECTION);glLoadIdentity();
glFrustum(-11,11,-11,11,30,200);

The result will be okay too.

Anybody know why? ( I can provide you tester program if needed)

because it’s the correct way to do things. Even better, try :

  
glMatrixMode(GL_PROJECTION);  
glLoadIdentity();
glFrustum(-11,11,-11,11,30,200);
glMatrixMode(GL_MODELVIEW); 
glLoadIdentity();
gluLookAt(8,6,84,	8,6,0,	0,1,0);

glPolygonMode( GL_FRONT_AND_BACK  , GL_LINE );
glBegin(  GL_POLYGON );
	glVertex3f(0,0,54);
	glVertex3f(16,0,54);
	glVertex3f(16,10,54);
	glVertex3f(8,16,54);
	glVertex3f(0,10,54);
glEnd();

Rob, Hi:

Well, thanks anyway for your reply. However, I am not sure you understand the problem or not. If I say method a work, you say because it is the correct way. If I say method b does not work, then you say because method b is wrong.

hehe…

[QUOTE]Originally posted by Rob The Bloke:
[QB][QUOTE]Originally posted by /* tSb */:
Gurus, Hi:

Originally posted by /* tSb */:
[b]Rob, Hi:

Well, thanks anyway for your reply. However, I am not sure you understand the problem or not. If I say method a work, you say because it is the correct way. If I say method b does not work, then you say because method b is wrong.

hehe…

[QUOTE]Originally posted by Rob The Bloke:
[QB][QUOTE]Originally posted by /* tSb */:
Gurus, Hi:[/b]
I understand your problem perfectly. You have mis-understood openGL transforms. read the transformations the other way round, ie

glTranslate*()
glRotate*()

the rotation occurs first, then the translation.

You assume it to be a bug, and i am telling you that that is the correct behaviour.

The projection matrix is not there to set the camera transform, it’s use is to set the projection by which 3D geometry will be transformed into 2D screen-space coords. The modelview is there for your 3D transforms (ie, use gluLookAt on the modelview matrix)

This:

glMatrixMode(GL_MODELVIEW);glLoadIdentity();
glTranslatef(-8,-6,-84);
glMatrixMode(GL_PROJECTION);glLoadIdentity();
glFrustum(-11,11,-11,11,30,200);

is exactly the same as

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-11,11,-11,11,30,200);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(8,6,84, 8,6,0, 0,1,0);

gluLookAt hides the fact that the camera does not move, the rest of the scene moves in the opposite direction. If you wanted to, you could also do :

glMatrixMode(GL_PROJECTION);glLoadIdentity();
glFrustum(-11,11,-11,11,30,200);
glMatrixMode(GL_MODELVIEW);glLoadIdentity();
glTranslatef(-8,-6,-84);

or even

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(8,6,84, 8,6,0, 0,1,0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-11,11,-11,11,30,200);

They are all identical. There is no bug!

Rob, Hi:

So far,
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
gluLookAt(8,6,84, 8,6,0, 0,1,0);
glMatrixMode(GL_PROJECTION); glLoadIdentity();
glFrustum(-11,11,-11,11,30,200);
and
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
glMatrixMode(GL_PROJECTION); glLoadIdentity();
glFrustum(-11,11,-11,11,30,200);
gluLookAt(8,6,84, 8,6,0, 0,1,0);

work.

However,
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
glMatrixMode(GL_PROJECTION); glLoadIdentity();
gluLookAt(8,6,84, 8,6,0, 0,1,0);
glFrustum(-11,11,-11,11,30,200);
does not work.

My question is that due the OpenGL pipeline is modleview -> project, so
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
gluLookAt(8,6,84, 8,6,0, 0,1,0);
glMatrixMode(GL_PROJECTION); glLoadIdentity();
glFrustum(-11,11,-11,11,30,200);

should equal
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
glMatrixMode(GL_PROJECTION); glLoadIdentity();
gluLookAt(8,6,84, 8,6,0, 0,1,0);
glFrustum(-11,11,-11,11,30,200); becuase the whole chain of matrix multiplication. model_view * projection

I don’t understand why
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
glMatrixMode(GL_PROJECTION); glLoadIdentity();
glFrustum(-11,11,-11,11,30,200);
gluLookAt(8,6,84, 8,6,0, 0,1,0);
work.

Because in my understanding gluLookAt translate the whole scene by (-8,-6,-84) and then define view volume in projection. What is the difference from translate the whole scence in model view and then only define view volume in projection. That is my point and that is why I am saying that is might be a bug.

thanks very much for your explanations.

It’s not a bug. The order is projection * modelview. Everything works in reverse !!!

Originally posted by /* tSb */:
[QB]Rob, Hi:

So far,
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
gluLookAt(8,6,84, 8,6,0, 0,1,0);
glMatrixMode(GL_PROJECTION); glLoadIdentity();
glFrustum(-11,11,-11,11,30,200);
and
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
glMatrixMode(GL_PROJECTION); glLoadIdentity();
glFrustum(-11,11,-11,11,30,200);
gluLookAt(8,6,84, 8,6,0, 0,1,0);

work.

Yes they do, however it’s projection * modelview!!!

This is how you should be doing it!

glMatrixMode(GL_PROJECTION); glLoadIdentity();
glFrustum(-11,11,-11,11,30,200);
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
gluLookAt(8,6,84, 8,6,0, 0,1,0);

remember, projection * modelview !!!

However,
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
glMatrixMode(GL_PROJECTION); glLoadIdentity();
gluLookAt(8,6,84, 8,6,0, 0,1,0);
glFrustum(-11,11,-11,11,30,200);
does not work.

yes, that’s modelview * projection. It is the wrong way around and thus it does not work!!!

My question is that due the OpenGL pipeline is modleview -> project, so
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
gluLookAt(8,6,84, 8,6,0, 0,1,0);
glMatrixMode(GL_PROJECTION); glLoadIdentity();
glFrustum(-11,11,-11,11,30,200);

This will work, but it really bad! In effect since you have specified the two transforms in the correct matrix stacks, the order is still projecton * modelview. That is fixed by OpenGL.

should equal
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
glMatrixMode(GL_PROJECTION); glLoadIdentity();
gluLookAt(8,6,84, 8,6,0, 0,1,0);
glFrustum(-11,11,-11,11,30,200); becuase the whole chain of matrix multiplication. model_view * projection

nope. Thats modelview * projection again! It is not the same as projection * modelview.

I don’t understand why
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
glMatrixMode(GL_PROJECTION); glLoadIdentity();
glFrustum(-11,11,-11,11,30,200); // projection transform
gluLookAt(8,6,84, 8,6,0, 0,1,0); // modelview transform
work.

Because it is correct, projection * modelview.

Because in my understanding gluLookAt translate the whole scene by (-8,-6,-84) and then define view volume in projection. What is the difference from translate the whole scence in model view and then only define view volume in projection. That is my point and that is why I am saying that is might be a bug.

The projection matrix stack is there for one reason and one reason only, to define the 3D to 2D projection. In effect it is the very last operation to take place, however since all transforms work in reverse it has to be the first one specified!

Rob, Hi:

Since the matrix in OpenGL is column major, so usually, I interpret the transformation as

Point/Vector(1x4) * Model_view * Projection * view port

Either this is an OpenGL bug or I am terribly missing something important. I wish OpenGL is open source now :slight_smile: This is why I believe

primitives * model_view * gluLookat * glFrustum

should work instead of

primitives * model_view * glFrustum * gluLookat

[QUOTE]Originally posted by Rob The Bloke:
[QB]It’s not a bug. The order is projection * modelview. Everything works in reverse !!!

Rob, HI: I have no doubt that your understanding is correct since that is what I got from OpenGL. One possible reason is that OpenGL internally still does

Matrix(4x4) * vector(4x1) (this will be different from what we generally do “row (dot) vector” to get the result

instead of

vector(1x4) * Matrix(4x4) ( natural multiplication )

That will fit perfectly with your notation
projection * model view and gluLookAt needs to be at the end of projection matrix stack

[QUOTE]Originally posted by Rob The Bloke:
[QB]The order is projection * modelview. Everything works in reverse !!!

There are open source OpenGL implementations. Look at Mesa for a prime example.

Rob is right. gluLookAt should be used on the modelview matrix (ever wondered why it is called modelview matrix ?). You can also find answers to your questions in the OpenGL spec itself.