PDA

View Full Version : Object Rotations in space



Cardinals33
03-29-2001, 09:03 PM
Hi. I am writing an engine that allows the user to fly through space with a six degrees of freedom engine. The engine works fine and I can easily change the camera angle based on user input but what I can't figure out how to do is to get an enemy fighter that the user rotate to fly towards the user when in attack mode and rotate to fly away when fleeing. I have a function to rotate the object which is a collection of triangles but because the rotations are performed in order the end result is not right. I've found I cannot compute the individual angles and then plug them into the rotation function as the object ends up facing a direction no where near what it should. What I am wondering is if there is a way to obtain an x, y and z angle that will actual rotate the object correctly? The rotation function i use looks like this:
WorldObject::RotateObject(int angleX, int angleY, int angleZ)
{
float temp_x, temp_y, temp_z;
int count;

for(count=0; count < model.NumVertices; count++)
{
temp_x = c[angleX] * model.Vertices_local[count].x - s[angleX] * model.Vertices_local[count].y;
temp_y = s[angleX] * model.Vertices_local[count].x + c[angleX] * model.Vertices_local[count].y;

model.Vertices_local[count].x = c[angleY] * temp_x - s[angleY] * model.Vertices_local[count].z;
temp_z = s[angleY] * temp_x + c[angleY] * model.Vertices_local[count].z;

model.Vertices_local[count].y = c[angleZ] * temp_y - s[angleZ] * temp_z;
model.Vertices_local[count].z = c[angleZ] * temp_z + s[angleZ] * temp_y;

model.Vertices_screen[count].x = (model.Vertices_local[count].x / model.scalefactor) + model.World_Pos.x; model.Vertices_screen[count].y = (model.Vertices_local[count].y/model.scalefactor) + model.World_Pos.y;
model.Vertices_screen[count].z = (model.Vertices_local[count].z/model.scalefactor) + model.World_Pos.z;

}
}

This works fine for one angle but when using multiple angles it gets screwed up. I know there are ways around this using quaternions and the like but how can that be applied to this since I need Euler angles to rotate the object? Thanks for the help.

-Dan

Korval
03-29-2001, 09:44 PM
First thing's first: don't do your own transformation. Especially without matrices the way you are doing it.

Let OpenGL do it. If you don't understand how transformation Matricies, glRotate, and other concepts work, then you should go find out about them first. Save this message until you are comfortable with standard OpenGL transformation matricies.

Getting an object to simply point in the right direction should be easy. Start by getting that to work first.

OK, let's say the front of the model is, in model space, facing down the +Z axis. This will be denoted by the vector Vm.

Now, in world space, you want the model to face some arbituary direction. Let's call this Vw. As long as this direction isn't exactly -Vm (ie, the -Z axis), then the following will work. You compute Vw based on your Euler angle rotations.

The axis of rotations (Vr) to feed glRotatef:

Vr = Vm X Vw (where X is the vector cross product). I'm not sure if you need to normalize this or not, but I'm sure a few experiments will get you the answer.

The angle is simply the angle between Vm and Vw. You can get this from:

arccos(Vm * Vw) (where * is the vector dot product and arccos is the inverse cosine function. Vm and Vw must be normalized).

Perform that angle/axis rotation, and you will be able to transform the model into the correct direction.

Go ahead and try this. Get this code working before adding the next part.

It should work, but it will likely also not quite be correct. The model will face the proper direction, but it won't be in the correct orientation (its up vector won't be where you want it).

Now, we correct this.

Compute Vu, the up vector as the model stands after the previous angle/axis rotation. This is not the up vector you want, but it is the up vector that you get after this rotation. This up vector comes from the model-space up vector. as it is transformed by the angle/axis rotation defined above.

Now, compute the up vector (Vuw) that you want the model to have. You can do this from your Euler angles.

The axis of rotation for this is the Vw, the front vector that you wanted in the first place. You see, you're just rotating around this vector to orient the model where you want it.

The angle is:

arccos(Vu * Vuw).

Make another glRotatef call, and you should be done.

Granted, I have not actually tried it, which is why I can't help you compute the vectors. But the theory seems sound, so it should work.

The other way to handle it is to convert the 3 Euler angle/axis rotations into quaternions, perform quaternion multiplication on them, and transform the resulting quaternion into a rotation matrix. This should get you the same answer.

Cardinals33
03-30-2001, 10:59 AM
I don't quite understand though. Once I have an axis and an angle, how can this be used to rotate a collection of points? Glrotatef is used for changing the view of the camera. This is not what I want to do. The object I want to rotate contains over 200 vertices, all of which have to be recomputed based on angles used to rotate them. That is why I have my own function. As far as I know, OpenGl cannot rotate a 3D model from 3DSMAX on its own. Is there some way of linking my model to OpenGL that I do not know about? Thanks for the help.

-Dan

Deiussum
03-30-2001, 11:57 AM
You don't seem to quite understand how OpenGL transformations work. For all practical purposes, there is no "true" camera in OpenGL. Things like gluLookAt can be used to simulate a camera, but basically, to emulate a camera, you just do the opposite to your scene that you would do for a camera. (Moving the "camera" back is going to give you the same result as moving the scene forward.)

You really should be using the OpenGL transformations like glRotate/glTranslate rather than recomputing your vertices. Even doing your own matrix functions would be better than recomputing all your vertex data.

Find a copy of the red book and read up on transformations as it's a basic concept in OpenGL that you really should have a grasp on before even thinking of creating your own engine. Also take a look at glPushMatrix/glPopMatrix as you will find these invaluable for many things.

Korval
03-30-2001, 12:11 PM
OK... You really need to do some more reading on OpenGL functions, but I'll explain some of it, to get you started.

When you send any vertex information, via immediate mode, vertex arrays, CVA, VAR, or display lists (or other extension), every vertex is transformed, first, by the modelview matrix, and then by the perspective matrix. So, as long as you set up your matrix stack properly, all you need to do is pass the vertices in model space, and it will handle the transformations.

As an added bonus, a card with hardware T&L will accelerate the transformations, alieviating the need for the CPU to do it.

Also, let me get rid of this misconception right now: the matrix stack has precious little to do with the camera. The OpenGL camera sits at the very bottom of the matrix stack. It is always situated at the origin, looking down... I think it is the +z axis, but I'm not certain. In any event, you rotate the world around the camera to change the viewpoint.

In any case, that's a conceptual notion. All you need to do is make sure that you use gluLookAt (or whatever camera functions you use to orient the camera) are the very first things in the matrix stack. Then, just do a push, set your model view matrices, and proceed as normal. When you need to change the camera (for the next scene), pop the last matrix, load the identity, and reset your camera matrix.

Let me state that another way, with pseudo code:


//At the start of a rendering loop:
glLoadIdentity()
SetupCamera //(do whatever camera direction setup here and load that matrix).
glPushMatrix()
//From here on, any glRotate, Translate, scale, MultMatrix functions will perform model-to-world transformations.
RenderScene()
//When you are finished rendering the scene, always remember to do this.
glPopMatrix()


Also, OpenGL neither knows, nor cares, where the model comes from. It could be from 3DSMax, Lightwave, Milkshape3D, etc, and it wouldn't know the different; it's all just vertices to OpenGL.

I would suggest reading up on the following functions: glRotate, glMultMatrix, glMatrixMode, glPushMatrix, glPopMatrix, and anything in the OpenGL documentation about the matrix stack. You'll find it very helpful.

Cardinals33
03-31-2001, 04:11 PM
Okay. The truth is I do know about glPushMatrix and glPopMatrix but have had troubles getting stuff to work correctly with them. To give you an example of something else I've been trying out, I want the user to be able to fire missiles that go straight off in the direction the user is facing. Movement of them is easy as I know how to obtain numbers from the OpenGL matrix to find the numbers to make it move forward. I then take these numbers and multiply them by a larger number for good movement speed. What I can't get to work is to have them face the correct direction. Without rotating and recomputing they of course always face the same direction so if you are facing 90 degrees to the right of where you started, you are looking at the left side of the missile. The code I've been trying basically changes the camera angle back to the original position so that it is looking at the back of the object and then renders it and then releases the matrix so the camera goes back to where the user wants it. The object does get rendered right however. The code looks like this:

//change the camera
glLoadIdentity()
glRotatef(angle,ax,ay,az);
glTranslatef(transx,transy,transz);

//for rendering the missile
glPushMatrix();
glLoadIdentity();

//quaternion to set camera to original view
Quaternion camquat(0,0,0);
camquat.GetAxisAngle(axis,angle);
axis.GetValues(ax,ay,az);
glRotatef(angle,ax,ay,az);

//compute where the object should be on
//the screen
object.GetObjPosition(objx,objy,objz);
object.Position(objx,objy,objz);
//render the object
object.RenderObject();
//release the matrix
glPopMatrix();

This causes the object to go all over the place and is only on the screen when facing your starting direction. I wonder is there something I am doing wrong? Thanks for any help you can give.

Warrior
03-31-2001, 09:13 PM
Cardinal -

Your saving the matrix state, but then reseting it. unless im missing something, that cant be right.
in fact, im pretty sure that cant be right.
try taking out the glLoadIdentity() after the glPushMatrix()