Mathematics for flying through a 3d space

Apprentice
Posts: 17
Joined: 2005.08
Post: #1
I've set myself a task to try and replicate the flight model found in space fighting games. I had a basic flight model working over a terrain, however in space things are a bit more complicated, especially if you take into consideration the Z rotation of the player. (Which some space fighters dont seem to - I've seen it working in some games though)

I was hoping that someone else has succeeded because I'm having a few troubles. I'd love some advice, pointers to algorithms, tutorials or source code for examples.

My overall design basically tracks the players x,y,z location and their x,y,z angle/rotation. Is this how others do it?

Current algorithm/concept:

// Take the movement of the trackpad (DeltaHoriz and DeltaVert) to generate the change in X and Y Angles
deltaY = deltaHoriz*cos(Zrot * PI/180) + deltaVert*sin(Zrot * PI/180);
deltaX = deltaVert*cos(Zrot * PI/180) + deltaHoriz*sin(Zrot * PI/180);
(I know this is wrong, but its close and it works in some situations)

//Code to set the X and Y rotation, and cope with the transition over 360 degrees.

// Then theres the basic movement code to move the player based on their rotations (the boolean differentiates between forward and back which may be removed in future - who's ever heard of a spaceship flying backwards? Smile )

if (Direction == true)
{
newX = X + sin(Yrot * PI/180)*BASE_SPEED*Ind_SpeedModifier;
newZ = Z - cos(Yrot * PI/180)*BASE_SPEED*Ind_SpeedModifier;
newY = Y - sin(Xrot * PI/180)*BASE_SPEED*Ind_SpeedModifier;
}
else
{
newX = X - sin(Yrot * PI/180)*BASE_SPEED*Ind_SpeedModifier;
newZ = Z + cos(Yrot * PI/180)*BASE_SPEED*Ind_SpeedModifier;
newY = Y + sin(Xrot * PI/180)*BASE_SPEED*Ind_SpeedModifier;
}

It's rather annoying - The trackpad code may work when the Zrot is up, but may be flipped at 90 degrees and fine when at 180 etc. So Im sure theres something wrong with my trackpad code's trig.
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #2
You want Quaternions. Googling will find you many, many explanations, most of which are completely uninteligible.

This one:
http://sacredsoftware.net/tutorials/Quat...ions.xhtml
was written by our resident tutorial writer "ThemsAllTook" -- if you have problems with it, he'll probably be around to help, at least Wink
Quote this message in a reply
Apprentice
Posts: 17
Joined: 2005.08
Post: #3
I thought I'd add to this topic as I learn things in case others want to do something similar.

I found this page useful: http://www.ogre3d.org/wiki/index.php/Quaternion_and_Rotation_Primer

Correct me if I'm wrong, Im still grasping on how to apply this math to practical application: From what this tells me, is that I can use quaternions to choose an arbitrary vector and rotate on that vector (as opposed to only x y z). So what I need to do is store where the player is (in a vector), where they are pointing (in a quaternion?) and create a combined x, y and z quaternion for where they want to point. Using this quaternion create an opengl rotation matrix and then rotate the world?
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #4
Sounds right.

Store where the player is (vector), their orientation (quaternion). Convert the inputs from Euler angles to quaternions, and multiply quaternions to get a new orientation. Convert the quaternion to a matrix for use with OpenGL.
Quote this message in a reply
isgoed
Unregistered
 
Post: #5
I use the math functions in quesa. http://www.quesa.org. You can just rip out (with some fixing of the source files) their quaternion functions and they are very complete.
Quote this message in a reply
Apprentice
Posts: 17
Joined: 2005.08
Post: #6
Code:
    Vector temp;
    temp.x = 1;
    temp.y = 0;
    temp.z = 0;
    
    Quaternion ChangeinX =  QuaternionFromAxisAngle(temp, deltaVert);

    
    temp.x = 0;
    temp.y = 1;
    temp.z = 0;
    
    Quaternion ChangeinY =  QuaternionFromAxisAngle(temp, deltaHoriz);
    
    Quaternion NewOrient = QuaternionMultiply(&ChangeinX, &ChangeinY);
    
    Orientation = QuaternionMultiply( &NewOrient, &Orientation);

I applied it as simply as I could but it doesnt seem to work. I did some cout debug statements after each, and it looks like the ChanginX, ChanginY are being created ok, NewOrient is being created, but when I look at the values for Orientation its always 0. Any ideas? Have I buggered it up?
(Orientation being created/defined elsewhere)
Quote this message in a reply
Apprentice
Posts: 17
Joined: 2005.08
Post: #7
addendum: I noticed where I initially set up Orientation, it was set to all zeros. if I put in any numbers the multiplication starts to work. Its wild and erratic, but at least its moving the screen.
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #8
all zeroes is not a unit quaternion. The identity quaternion (no change in orientation) has 1 in the w component, and 0s in x, y and z.
Quote this message in a reply
Apprentice
Posts: 17
Joined: 2005.08
Post: #9
I'm getting closer:
Once I started converting the trackpad input into radians it started to actually resemble a proper "looking around" function.
There is one strange problem though. As I look around there is an ever so slight change to the z rotation.

e.g. (The debug ouput of when I moved 1 degree on X and 1 degree on Y)
(X Y Z W)
ChangeinX: 0.00872654 0 0 0.999962
ChangeinY: 0 0.00872654 0 0.999962
NewOrient: 0.0087262 0.0087262 7.61524e-05 0.999924
Orientation: 0.0087262 0.0087262 7.61524e-05 0.999924

Since Im still in the dark on how quaternions work (im getting there slowly), I was wondering why the Z was changed (7.61524e-05) ever so slightly.

(Im using the quaternion/vector code from the tutorial OneSadCookie linked to )
(Apologies for the stupid questions)
Quote this message in a reply
Moderator
Posts: 3,573
Joined: 2003.06
Post: #10
Lunatic Wrote:Since Im still in the dark on how quaternions work (im getting there slowly), I was wondering why the Z was changed (7.61524e-05) ever so slightly.
A true understanding of how quaternions work in the extra dimension is past my comprehension at this point. Most of us just accept the techniques and math as a black box and go with it.

I admit that I didn't read very carefully what you are describing, but floating point drift over time is pretty common in my experience with quaternions. Depending on what you're trying to do, you can periodically reset them to synch with correct values.
Quote this message in a reply
Apprentice
Posts: 17
Joined: 2005.08
Post: #11
Code:
    deltaVert = deltaVert * PI/180;
deltaHoriz = deltaHoriz *  PI/180;
    
    Quaternion NewOrient;
    Quaternion ChangeinX;
    Quaternion ChangeinY;

    NewOrient.w = 1;
    ChangeinY.w = 1;
    ChangeinX.w = 1;

    Vector temp;
    temp.x = 1;
    temp.y = 0;
    temp.z = 0;
    
    ChangeinX =  QuaternionFromAxisAngle(temp, deltaVert);
    
    NewOrient = QuaternionMultiply(&NewOrient, &ChangeinX);
    
    temp.x = 0;
    temp.y = 1;
    temp.z = 0;
    
    ChangeinY =  QuaternionFromAxisAngle(temp, deltaHoriz);
    
    NewOrient = QuaternionMultiply( &NewOrient, &ChangeinY);

    NewOrient.z = 0;
    
    Orientation = QuaternionMultiply( &Orientation, &NewOrient);
    Orientation.z = 0;

So. This is where I am now.
I create the X Quat, and multiply it with the New Orientation.
I create the Y Quat, and multiply it with the New Orientation.
I then multiply the New Orientation with the Old Orientation.

This seems to go ok, (i.e. I can look around) although Im about to lose the rest of my hair in frustration since I still seem to get the gimble lock effect - I was really hoping that Quaternions would make it so that no matter which way I was pointing, I could move the mouse up/down/left/right and the world would move accordingly Rasp
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #12
Are you trying to maintain a consistent up vector, or do you want the player to be able to rotate freely on any axis, even if they end up upside-down?

I'm not quite sure what you're trying to accomplish by setting the Z component in NewOrient and Orientation to 0. That seems a bit dodgy. Also, if these are structs (as opposed to C++ objects with constructors that initialize everything to 0), you'll need to set the X, Y, and Z components of NewOrient, ChangeInX, and ChangeInY to 0 after you declare them. If you don't, you run the risk that they'll contain random memory garbage at runtime.

Lunatic Wrote:This seems to go ok, (i.e. I can look around) although Im about to lose the rest of my hair in frustration since I still seem to get the gimble lock effect - I was really hoping that Quaternions would make it so that no matter which way I was pointing, I could move the mouse up/down/left/right and the world would move accordingly Rasp
Don't give up hope yet - Quaternions do exhibit gimbal lock when used in certain ways, but used properly, they don't. It can take a little while to wrap your head around how to use them properly, but it's worth it when you get there. Smile
Quote this message in a reply
Apprentice
Posts: 17
Joined: 2005.08
Post: #13
They're just structs at the moment, nothing too fancy. Just want to get the simple method working first.

This code is meant to handle simple mouse look. I.e. If the space ship is looking in any direction, you still should be able to look left/right/up/down. I eventually want to incorporate twisting along the Z axis once I get the mouselook working.

The setting of Z to 0 was to counter the strange increments and decrements to the Z axis that were happening when I was multiplying the Quaternians together.

You say that they do exhibit the lock effect in certain ways - is there some sort of set of rules I can use to avoid it? What can I do better to use them "properly"? Smile Am I on the right track at least?
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #14
You certainly seem to be on the right track. You'll usually only get gimbal lock if you try to use quaternions the same way as euler angles; IE having one quaternion each for pitch, yaw, and roll. I've actually seen people try to do this.

Looking over my own mouselook code, it looks like I rotate first on the Y axis, then on the X axis. Try multiplying NewOrient by ChangeInY before ChangeInX, and see if it helps? Also, I'd suggest commenting out NewOrient.z = 0; and Orientation.z = 0; to make sure they're not having unexpected side-effects.
Quote this message in a reply
Apprentice
Posts: 17
Joined: 2005.08
Post: #15
Once more I am closer...

The mouse look seems to be avoiding any locking effect which is good. However, one last pain exists!
There is something wierd about how the angles are being calculated that causes a Z rotation effect, without there being any Z rotation. Let me explain better..

If I perform little circles in the centre of the track pad, the screen moves around in a circle but also seems to rotate around the Z axis. The debug output of all the quaternions indicates no Z component value for any - yet somehow I can turn upside down Smile

I did take on board the comments about applying the Y before the X, I also changed the order of the mulitplication parameters. There was also some fixing of the model view and projection matrixes, I had them in the "wrong order".
Quote this message in a reply
Post Reply