looooooooooooooong story even though it looks like it’s simple!

let’s start with the super simple helloworld program!

#include "windows.h" #include <gl/GL.h> #include <glut.h> void display(void) { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 0., 0.); glBegin(GL_POLYGON); glVertex3f(0., 0., 0.0); glVertex3f(1., 0., 0.0); glVertex3f(1., 1., 0.0); glVertex3f(0., 1., 0.0); glEnd(); glFlush(); } void init(void) { glClearColor(0.0, 0.0, 0.0, 0.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); //glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(250, 250); glutInitWindowPosition(100, 100); glutCreateWindow("hello"); init(); glutDisplayFunc(display); glutMainLoop(); return 0; }

okay, you will get something like above.

Let’s start to analyze….

first, don’t think anything about matrix…. just think about it like a real world….

check the src code, we are not setting anything except the window size (glutInitWindowSize), actually, you could even try not to call this, to see the window size you will get….

under the hood, what OpenGL does is:

1) draw the rectangle as what you wanted (size is 1).

2) put this rectangle into a 3D box (later, we will call it as Frustum, here, it’s ortho Frustum), OpenGL has a default size 2X2X2 for this frustum (two corners are: (-1,-1,-1)(1,1,1)). Anything out of this frustum is clipped! You can verify this by changing the rectangle size/location, for example, change the z value to be >1 or <-1, you will see that your rect is gone!

3) your eye is located at (0,0,1) and looking at (0,0,-1) direction. +Y is your up direction. Assume that you have a 2X2 screen at (0,0,1) location, then, everything inside frustum will be projected onto your screen.

4) finally, your 2X2 size screen will be projected to the viewport (your window: 250X250).

5) now, it’s done!

- First, let’s say, we create a super simple openGL example, only show a cubic box, don’t set any angles (no transform, glulookat, glfrustum or glortho…). in this case, what’s happening?

all matrix should be unit now, if you use

glGetFloatv(GL_MODELVIEW_MATRIX)

to check or check other matrix, you will see.

question: then, why we are seeing XY plane along -Z direction?

answer: this is what openGL by default uses, nothing related to matrix!!! my understanding is, by default, Z buffer is along Z direction, opengl will project all entities to Window CS, right? Windows CS is only a plane, then, opengl maps all entites to XY plane…. see, the whole process doesn’t need any matrix calculation.

by default now, gluLookAt -Z direction, and Y is up direction, which is the same w/ our regular 2D CS.

Orthographic (size 2 cubic, centered at origin) instead of Perspective Projection is used, we will apply orthographic matrix to this scenario later.

2.

Now, let’s start step by step slowly.

2.1) Model Matrix

say, now, let’s call glRotatef(30, 0, 0, 1)

which means, to rotate object 30 degree about Z axis.

this is the same w/ any transformation matrix, it’s the same as:

P2 = Matrix_Rotation(30, Z) * P1

if we call one more glRotatef(45, 1, 0, 0)

like this:

glRotatef(30, 0, 0, 1);

glRotatef(45, 1, 0, 0);

glutSolidTeapot(2.0);

it means,

P2 = Matrix_Rotation(45, X) *Matrix_Rotation(30, Z) * P1

which further means, rotate 30 about Z first, then, rotate 45 about X

**2.2) View Mtrix**

there is no view matrix!

model matrix & view matrix are together called modelview matrix. And the only way to change “view matrix” here is to use gluLookAt(…)

GLfloat mvMtx1[16];

gluLookAt (0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0);

GLfloat mvMtx2[16];

glGetFloatv(GL_MODELVIEW_MATRIX, mvMtx1);

gluLookAt (0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.866, 0.5, 0.0);

glGetFloatv(GL_MODELVIEW_MATRIX, mvMtx2);

what we will get (because Opengl uses column per column for matrix, so, what we will get in memory for mvMtx1 is first column, second column…., not as what we normally do in math: first row, second row….):

mvMtx1:

[ 1 0 0 0

0 1 0 0

0 0 1 0

0 0 0 1]

and mvMtx2:

0.5 -0.866 0 0

0.866 0.5 0 0

0 0 1 0

0 0 0 1

which means, what we got is the matrix_rotation(Z, 60), which is correct, right? because our UP direction is 30 degree from X axis, which is to rotate 60 from old UP direction (Y), negative direction, which is the same w/ rotate model negative 60 about Z.

reference: rotation matrix:

okay, now, the problem comes:

what if we set:

gluLookAt (1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);

I mean, use a random lookat direction, then, what’s the mvmatrix?

see songho’s tutorial, which is very clear:

http://songho.ca/opengl/gl_lookattoaxes.html

but his code has bugs….. see comments

actually, the man page is very clear already!

http://www.manpagez.com/man/3/gluLookAt/

If you are not interested in some super detailed things, skip the following section about gluLookat().

===================>start

Now, we think we are clear.

Okay

Question 1, to make the same view for the given lookat directions (both forward & Up dir), how to rotate CS axis by axis?

question 2: to make the same view for the given lookat directions (both forward & Up dir), how to rotate model axis by axis? If you can make it, is ur algorithm robust?

Now, let’s start this long topic.

Answer to question 2:

First, check this out: Euler Angle.

https://en.wikipedia.org/wiki/Euler_angles

which means, for any position and orientation, we can always find Euler Angle (say, we use ZXZ here), which means, we can for sure find an exact set of Euler angle for question 2, right?

Then, it’s simple now.

Actually, glulookat() means, we want to create a new CS whose:

X: forwardDir ^ UpDir = (centerPos – eyePos) ^ UpDir

Y: UpDir

Z: X ^ Y

then, just simply use algorithm in “Geometric Derivation” in Euler Angle wiki page to make it, very simple!

I didn’t try to use matrix to calculate Euler angles or Tait-Brian angles, it should work, too.

Now, answer to Question 1:

There are always to ways to think about transformation: transform models and transform CS (many books mentioned this, normally, the latter way is more used in books about robot kinematics, etc. Even in <<Computer Graphics: Principles and Practice in C>>, it also mentioned this in the chapter about transformation very shortly.)

If we use the 2nd way (transform CS), we could easily see that how transformation matrix comes from new axis.

say, if rotate CS about Z axis by -30 degree, then, got the new CS: CS1. Let’s call old CS as: CS0.

then, X1 wrt CS0 is: cos(a) -sin(a) 0

Y1 wrt CS0 is: sin(a) cos(a) 0

Z1 wrt CS0 is : 0 0 1

then, you get rotation_Z matrix, right?

same idea, no matter how many matrices you rotate, you can always apply the same rule…. that’s why you can get glulookat matrix like that…………….

…..to be continued………….

end<========================

**2.3) **