Problems with camera movement and rotation.

Started by
13 comments, last by Wodzu 14 years, 1 month ago
Hi guys. I am trying to learn how to operate my camera in OpenGL. However I think I have problems with understaind the translations in local \ global coordinate system. I want to move my camera freearly around a cube which is located at (0,0,-5). However instead of moving my camera the sceene looks like the cube is moved to the orgin of global coordinate system. Also the rotation of my camera doesn't look "natural" to me. Something is wrong with that also. Here is a crucial part of my code: procedure ReSizeGLScene(Width, Height: Integer); cdecl; begin if Height = 0 then Height := 1; glViewport(0, 0, Width, Height); glMatrixMode(GL_PROJECTION); glLoadIdentity; gluPerspective(45, Width / Height, 0.1, 1000); glMatrixMode(GL_MODELVIEW); glLoadIdentity; end; procedure GLKeyboard(Key: Byte; X, Y: Longint); cdecl; begin if Key = 27 then Halt(0); case Key of 97: CameraPosition.Z := CameraPosition.Z + 1; 122: CameraPosition.Z := CameraPosition.Z - 1; end; end; procedure GLSpecialKeyboard(Key: Longint; X, Y: Longint); cdecl; begin case Key of GLUT_KEY_LEFT: CameraAngle.Y := CameraAngle.Y - 1; GLUT_KEY_RIGHT: CameraAngle.Y := CameraAngle.Y + 1; GLUT_KEY_DOWN: CameraAngle.X := CameraAngle.X + 1; GLUT_KEY_UP: CameraAngle.X := CameraAngle.X - 1; end; end; procedure DrawGLScene; cdecl; begin glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glLoadIdentity; glRotatef(CameraAngle.Y, 0, 1, 0); glRotatef(CameraAngle.X, 1, 0, 0); glTranslatef(CameraPosition.X, CameraPosition.Y, CameraPosition.Z); glutWireCube(1); glutSwapBuffers; end; Also, the full working program can be downloaded here: http://www.speedyshare.com/files/21386187/MyCamera.zip The effect which I want to achive is to point my camera towards some point in scene and move camera towards that point. Thanks for your time.
Just started...
Advertisement
If you want to look at a specific object/position, you can just use the glLookAt() at function. However, if you're trying to freely rotate your camera, the rotation matrix based on the rotation of the camera won't do. You must use the inverted matrix of the camera's rotation.

EDIT: If the inverted matrix is your solution, let me know. It's a bit of a pain in the ass and I've got a working implementation here somewhere that I can post.
Quit screwin' around! - Brock Samson
Thank you for your reply.

I want to move my camera freerly like in a 3D Space game.

Could yu give me an example how to use such inverted matrix?

Firstly I need to create a rotation matrix umm...from my angles?
Than I need to converted it to the inverted matrix?
And than I need to multiply that matrix by the current view matrix?

EDIT: Yes, that is exactly what I need, thank you for your help. But will I be able to understand your implementation? I mean I need to learn how to use such matrix to achieve a given result.

[Edited by - Wodzu on March 12, 2010 8:40:14 AM]
Just started...
I'm probably jumping ahead and should be careful not to make this more confusing than it really is. It's been a while since I've had to delve into OpenGL so I need to get my bearings.

Okay, I see you're using a glRotatef() call for each axis. This is a pretty straightforward method so you can scratch my earlier comment about inverted matrices. This method (for me anyway) tends to require some trial and error. For instance, (and this is going on memory alone) you may need to negate the coordinates before translating:
glTranslatef(-CameraPosition.X, -CameraPosition.Y, -CameraPosition.Z);

instead of:
glTranslatef(CameraPosition.X, CameraPosition.Y, CameraPosition.Z);

If you think about this logically, the objects in your screen space appear to move in the opposite direction of the camera movement. Looking out of a train window (left) as the train moves forward (right), the train station appears to move opposite (left).

Also, I don't see where you're cube's position is being set and it appears that the cube should be at origin. To shift the position:

glPushMatrix (); //preserve the camera rotation matrix
glTranslatef (0.0, 0.0, -5.0); //shift the cube position
glMultMatrixf (Obj->GetRotation()); //if you need to rotate the cube, do it here
glutWireCube (1); //same as before
glPopMatrix (); //retrieve the camera rotation matrix

Hope this helps!
Quit screwin' around! - Brock Samson
In case you need it at any time in the future, here's an implementation of the invert matrix function in BASIC:

SUB TPLInvertMatrix (Dest AS SINGLE PTR, Source AS SINGLE PTR)	DIM X AS INTEGER	DIM Y AS INTEGER	DIM Index AS INTEGER	DIM Minor(11) AS SINGLE	DIM Adjoint(11) AS SINGLE	DIM AS SINGLE Determinant = Source[0] * (Source[5] * Source[10] - Source[9] * Source[6]) - _					Source[4] * (Source[1] * Source[10] - Source[9] * Source[2]) + _					Source[8] * (Source[1] * Source[6] - Source[5] * Source[2])	DIM AS SINGLE DetRec = 1.0 / Determinant  'Determinant reciprocal	'Calculate minors of source matrix	Minor(0) = Source[5] * Source[10] - Source[9] * Source[6]	Minor(1) = Source[4] * Source[10] - Source[8] * Source[6]	Minor(2) = Source[4] * Source[9] - Source[8] * Source[5]	Minor(4) = Source[1] * Source[10] - Source[9] * Source[2]	Minor(5) = Source[0] * Source[10] - Source[8] * Source[2]	Minor(6) = Source[0] * Source[9] - Source[8] * Source[1]	Minor(8) = Source[1] * Source[6] - Source[5] * Source[2]	Minor(9) = Source[0] * Source[6] - Source[4] * Source[2]	Minor(10) = Source[0] * Source[5] - Source[4] * Source[1]	'Calculate cofactors and adjoint in one shot	Adjoint(0) = Minor(0)	Adjoint(1) = -Minor(4)	Adjoint(2) = Minor(8)	Adjoint(4) = -Minor(1)	Adjoint(5) = Minor(5)	Adjoint(6) = -Minor(9)	Adjoint(8) = Minor(2)	Adjoint(9) = -Minor(6)	Adjoint(10) = Minor(10)	'Finally, we find the inverse by dividing the adjoint by 	'the determinant |A|.  Since you can't divide a matrix, 	'we simply multiply each value by the reciprocal.	FOR Y = 0 TO 2		FOR X = 0 TO 2			Index = Y * 4 + X			Dest[Index] = DetRec * Adjoint(Index)		NEXT X	NEXT Y	'Last column can simply be copied	Dest[3] = Source[3]	Dest[7] = Source[7]	Dest[11] = Source[11]END SUB


This inverts ODE (physics) matrices so the format is different than OpenGL. Here's another function that performs the conversion:

SUB RenderConvertODEMatrix (Source AS dReal PTR, Dest AS GLFloat PTR)	Dest[0] = Source[0]:Dest[1] = Source[4]:Dest[2] = Source[8]:Dest[3] = 0	Dest[4] = Source[1]:Dest[5] = Source[5]:Dest[6] = Source[9]:Dest[7] = 0	Dest[8] = Source[2]:Dest[9] = Source[6]:Dest[10] = Source[10]:Dest[11] = 0	Dest[12] = 0:Dest[13] = 0:Dest[14] = 0:Dest[15] = 1END SUB
Quit screwin' around! - Brock Samson
Thank you codrex75 for the answers.

However you said that I do not need the inversion matrix but then you propose me to use glMultMatrixf(). So I am totaly lost now...
Just started...
A little primer to help your understanding:

So when dealing with cameras and objects, you have two matrices that you need to worry about. One is the Model Matrix, and the other is the View matrix. These are often combined together to get the "ModelView" matrix that you will often hear of.

When you define a mesh, all of the coordinates will typically be in "Object Space". This defines the location of vertices relative to the origin of your object. The object space coordinates have no information about where the object is in the "World" (or Global Coordinate System). If you have a cube at 0,0,0 and you translate the cube to another position, the object space coordinates are always the same, because they only define vertices relative to the object.

So if we want to move our cube to a new location, we need to find a way to move each vertex from "Object Space" into "World Space". This is done via a Model Matrix. If you want to translate your object 5 units to the right, then you define a Transformation Matrix that defines a translation to the right by five units. This matrix can be 'M', or our model matrix. So now if we have a point 'p' in object space, and we want to move it into world space 'P', we transform it with the Model matrix like so: P = Mp. Your model matrix can contain as many translations, rotations, scalings as you need. If you want to Translate, then rotate, then scale your model, via matrices To (T object), Ro, So, then your modelview matrix is constructed M = To*Ro*So.

But what about the view matrix? Because there is no camera construct in OpenGL, we must transform our vertices again into a new space called "Eye Space". The viewport in opengl always looks out from 0,0,0 in the negative z direction, so we must "transform the entire world" so that it looks accurate from that space.

As coderx was describing with the train analogy, you move your view in openGL by moving the entire world in the opposite direction. When you turn your head to the right, this is exactly the same thing as if the entire world is rotating to the left. When you move your eyes up, it is also as if the entire world is moving down. So however we want to move our "camera", we must transform the world by the inverse of this movement.

So we need to come up with a matrix V (view matrix), that transforms our world coordinates into eye coordinates. Using our original point p and model matrix M, the equation now looks like this: P = VMp, where P is now in eye space.

Now remember that V is supposed to be the inverse of the camera movement that we want. Lets say what we really want to do is move our camera up and then rotate it 45 degrees downward to get a birds eye view of our world. If we treat the camera like an object, then we want to transform our camera by a translation (Tc) and a rotation (Rc): C = Tc*Rc.

Now transform matrix C will take an object and translate it up and rotate it. But what we really want is the inverse of C, which will be our view matrix. inverse(C) = C' = V

Now to find C' (also known as V), you can either invert the matrix C using matrix inversion methods, or you can just compute it from the original transformations. Because of the properties of matrices, this holds true:

C' = (TcRc)' = Rc'Tc'

Where Tc and Rc are our camera transforms. However Tc' and Rc' are very easy to calculate. The inverse of a translation is just a translation in the opposite direction, and the inverse of a rotation is just a rotation in the opposite direction.

So now you can transform your original vertex into eye space like so:

P = Rc' * Tc' * To * Ro * So * p

or

P = VMp

You can either construct this by building the "VM" matrix yourself, or you can build it with opengl transform functions. For example:

glLoadIdentity(); //Modelview matrix now identity//Setup the cameraglRotatef(negative camera rotation) //Modelview matrix now = Rc'glTranslatef(negative camera movement) //Rc' * Tc'//Setup the model matrixglTranslatef(object translation) //Rc' * Tc' * ToglRotatef(object rotation) //Rc' * Tc' * To * RoglScalef(object scale)//Rc' * Tc' * To * Ro * So//Now send your object space vercices, which are translated into eye spaceglVertex(p) // P = Rc' * Tc' * To * Ro * So * p

And that concludes the basics of opengl cameras :)

I know it is confusing at first, but after you work at it for a while it will make more sense.
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game
Thank you karwosts for you explanation and your time.

You expleined it very nicely even nicer the the OpenGL book itself ;)

There is one thing strictly mathematical which I do not know how to calculate.
I have some ideas but I do not want to reinvent the wheel.

Lets assume that I've rotated mine camera view about three angles. So I have now new vector pointing in space. I would like to move my camera along this vector by some unit distance. So I need to know how much I must translate in X,Y,Z-plane.

I know how to do this in 2D-space but I do not know how to do this in 3D, atleast in easy way.

The idea which I have is that:

I have old vector and 3 angles. I need to rotate this vector and calculate it's new coordinates. When I have new coordinates I normalize the vector and multiply by the unit distance. Then I add this value to the calculated vector.

But this is a lot of work and I am redoing some thing which is already done by the OpenGL.

How to do it in a simpler way? The ideal way would be to know only how much I need to translate without calculating the new vector by myself.

Regards.
Just started...
Actually this information is stored inside the model matrix for you and easy to pull out. When you look at the actual elements of the matrix, this is what they represent:

 0  4  8 12  1  5  9 13 2  6 10 14 3  7 11 15Rx Ux Ox PxRy Uy Oy PyRz Uz Oz Pz 0  0  0  1


So elements 0,1,2 are the Right Vector (Rx, Ry, Rz), 4,5,6 is the Up Vector, and 8, 9, 10 is the Out Vector (or direction). 12,13,14 contain your translation. So whenever you perform the matrix math you already have your out vector. If you want to use the OpenGL transformations instead of performing the matrix op's yourself (preferred way is to do it yourself, but that is more advanced), you can download the matrix with glGetFloatfv and examine it's elements.


[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game
Thank you karwosts :)

I have now a working camera however it is made after trials and errors and I feel that i know only in half how it works :|

I know that the order of command isue is crucial due to the matrix multiplication.
Howeve I can not find a logic in it. I wanted to compare two thhe most simple cases to observe how to rotation occurs.

Here are the cases:

CASE 1:

glLoadIdentity;
gluLookAt(0,0,5, 0, 0, 0, 0, 1, 0);
glRotatef(90, 1, 0, 0);
glRotatef(90, 0, 1, 0);
glutWireCube(1);

CASE 2:

glLoadIdentity;
gluLookAt(0,0,5, 0, 0, 0, 0, 1, 0);
glRotatef(90, 0, 1, 0);
glRotatef(90, 1, 0, 0);
glutWireCube(1);

So I only switched the order of rotation commands.

What I find illogical and impossible to understand (after rotating this damn cube for hours;)) is that:

In first case when I am thinking in terms of grand fixed orgin the command are issued in the reversed order, so:

1. Cube is drawn
2. Cube is rotated around OY counterclockwise by 90 degrees.
3. Cube is rotated around OX counterclockwise by 90 degrees.
4. Cube is translated -5 units in Z direction from the orgin.

Am I thinking correct?

But the same thinking in CASE two fails me, here it is:

1. Cube is drawn.
2. Cube is rotated around OX counterclockwise by 90 degrees.
3. Cube is rotated around OY counterclockwise by 90 degrees.
However the effect is different from expected! It looks like the step 2 (rotation around OX) also rotated the OY axis by 90 degrees! But in first case rotation around OY did not rotate the OX axis. This is the thing which I do not udenrstand.

Why in the first case the coordinate system has not been rotated with object and in the second case coordinate system has been rotated.

I can not see the logic here. Eiter in both cases the coordinate systems should be rotated with an object or they should stay fixed.

I am lost... :|
Just started...

This topic is closed to new replies.

Advertisement