#### Archived

This topic is now archived and is closed to further replies.

# Quaternions: A Real Pisser

This topic is 6059 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I am writing a little space sim (for my personal game development education only) and I know Quaternions are diffinately the way to go...I''ve read just about every tutorial I can find on them, and I''ve written a class that can do all the mathmatical functions with Quaternions, but I have no idea how to actually use it all =). I''m tired of tutorials saying "...and so the unit vector can do blah blah here''s how to do blah blah but we''re not going to tell you this and that." This and that being how to actually rotate the quaternion, and get that rotation to rotate an object or camera. Can anyone tell me, or point me to a tutorial that will tell me "So, to rotate a quaternion using pitch, yaw, and roll..." and "Now use glLoadMatrix/translate+rotate on this..." I''d very much appreciate it. Thanks!

##### Share on other sites
I''ll second that!

It seems we''re both doing very similar thing - i''m doing a kind of Elite clone, just to learn OpenGL and C ... and i''ve had much the same problems!

One suggestion ... try mailing Propuslor propulsor@web-discovery.net ... from the GLHorizon site ... worth checking out! He sent me some stuff, which i haven''t had time to look at yet ... thanks for that Propuslor!!!

Regards

Shag

##### Share on other sites
Thanks Shag, I''ll see if he emails me some stuff to =)

##### Share on other sites
Once upona a time I was working on a programming site but the lack of interest in it caused me to abandon it. I do however have some info on quaternions there, including there use in a flight simulation type environment...
The main page is at
http://tannara.net/
the page I''m specifically referancing is here...
http://tannara.net/Graphics/Theory/3d_viewing_in_a_flight_simulations.htm

##### Share on other sites
Assuming you have the quat-math functions and that they work:

what i do is the following:

I have 2 quats defined at all times. One holds the current orientation in the univers and the other holds what i call dOrientation (ie the difference in orientation from the last frame to the current).

Between frames i find out how much rotation is needed around the 3 axis (Euler). I create dOrientation from these 3 angles. Perform the multiplication: dOrientation*Orientation (in that specific order). Convert the dOrientation to AxisAngle and use glRotate to perform the AxisAngle-rotation.
Finally copy the values from dOrientation to Orientation.
Repeat each frame.

I had some problems because, first, i didnt use the dOrientation to hold the temporary rotation (still got that damn Gimbal-lock), and second i was multiplying in the wrong order (quat-multiplication is not commutative(called that in english ?)).

If you still have problems let me know and ill post some code.

Good luck

##### Share on other sites
Another thing which caused me some problems was finding the vector of translation from a quaternion. What i used is the following set of equations.

dirX = 2.0 * (x * z - w * y)
dirY = 2.0 * (y * z + w * x)
dirZ = 1.0 - 2.0 * (x * x + y * y);

Where w, x, y, z are the components of the Orientation quat.

Hope that helped .

##### Share on other sites
Darn, I have how no idea how to perform Quaternion-to-Euler conversion...I have Quaternion-to-Matrix Conversion, and thats what I''ve been using, but when I rotate the Quaternion, some really gnarly things happen to my skybox (the only object in the game right now). Things like two oppisite sides of the skybox coming closer together, and eventually going through eachother only to go back to normal, then back to almost touching eachother...Anyone else had this problem?

##### Share on other sites
Here's my quat functions. feel free to use them even though they could use some optimization.

  class Quaternion{public: float w,x,y,z; float qLength; Quaternion(float newW, float newX, float newY, float newZ); Quaternion(); void Normalize(); void toAxisAngle(float *result); void MultQuat(Quaternion *q); void EulerToQuat(float aX, float aY, float aZ); void LoadIdentity();};

  #include "stdafx.h"Quaternion::Quaternion(float newW, float newX, float newY, float newZ){ this->x = newX; this->y = newY; this->z = newZ; this->w = newW; this->qLength = (float)sqrt(this->x*this->x + this->y*this->y + this->z*this->z + this->w*this->w);}Quaternion::Quaternion(){ this->x = 0.0; // create mult identity quaternion this->y = 0.0; this->z = 0.0; this->w = 1.0; this->qLength = 1.0;}void Quaternion::Normalize(){ float l; l = (float)1.0/this->qLength; this->x *= l; // mult by inverse length to normalize this->y *= l; this->z *= l; this->w *= l; this->qLength = 1.0f;}void Quaternion::toAxisAngle(float *result){ float AxisAngle[4]; float scale; scale = this->x*this->x + this->y*this->y + this->z*this->z; AxisAngle[0] = (float)(2*acos(this->w)); // angle to rotate AxisAngle[1] = this->x / scale; // next 3 lines is x,y,z of vector to rotate about AxisAngle[2] = this->y / scale; AxisAngle[3] = this->z / scale; result[0] = AxisAngle[0]; result[1] = AxisAngle[1]; result[2] = AxisAngle[2]; result[3] = AxisAngle[3];}void Quaternion::MultQuat(Quaternion *q){ float tempx, tempy, tempz, tempw; tempw = this->w*q->w - this->x*q->x - this->y*q->y - this->z*q->z; tempx = this->w*q->x + this->x*q->w + this->y*q->z - this->z*q->y; tempy = this->w*q->y + this->y*q->w + this->z*q->x - this->x*q->z; tempz = this->w*q->z + this->z*q->w + this->x*q->y - this->y*q->x; this->x = tempx; this->y = tempy; this->z = tempz; this->w = tempw; this->qLength = (float)sqrt(this->x*this->x + this->y*this->y + this->z*this->z + this->w*this->w);}void Quaternion::EulerToQuat(float aX, float aY, float aZ){ this->y = 0.0; //lets make sure that quat is initialized this->z = 0.0; Quaternion* qY = new Quaternion(); Quaternion* qZ = new Quaternion(); this->x = sin(aX/2); this->w = cos(aX/2); qY->y = sin(aY/2); qY->w = cos(aY/2); qZ->z = sin(aZ/2); qZ->w = cos(aZ/2); this->MultQuat(qY); this->MultQuat(qZ); this->qLength = (float)sqrt(this->x*this->x + this->y*this->y + this->z*this->z + this->w*this->w);}void Quaternion::LoadIdentity(){ this->w = 1.0; this->x = 0.0; this->y = 0.0; this->z = 0.0;}

Edited by - newdeal on July 17, 2001 1:50:04 PM

##### Share on other sites
Dave: quaternion to euler, like matrix to euler, doesn''t really work because you have to use inverse trig functions - because their domain is limited you aren''t guaranteed to get out the values that went in. It hasn''t mattered to me though, as I''ve yet to find a use for quaternion to euler conversion.

NewDeal: Similarly if you assume an object''s initial up vector (0,1,0), and left vector (1,0,0) then after being rotated by a quaternion:

up.x = 2 * (x*y - w*z)
up.y = 1 - 2 * (x*x + z*z)
up.z = 2 * (y*z + w*x)

left.x = 1 - 2 * (y*y + z*z)
left.y = 2 * (x*y + w*z)
left.z = 2 * (x*z - w*y)

You can derive those from standard quaternion to matrix conversion code.

##### Share on other sites
A couple things I forgot.

Like NewDeal suggested, try converting from quaternion to axis-angle, instead of quaternion to matrix. I find it much easier, and you''ll probably save some operations.

Ok now for how exactly you rotate stuff with quaternions. Each frame you decide how much you want your object to yaw, pitch, and roll based on user input. For example if the user moves the mouse 5 units left you could say that''s a yaw of 5 degrees. Anyway, you convert these yaw/pitch/roll angles (euler angles) to a quaternion. To actually rotate the object you just multiply this yaw/pitch/roll quaternion with the object''s current orientation.

quaternion temp = eulerAnglesToQuaternion(yaw, pitch, roll);
ship.orientation = temp * ship.orientation;

To display an object...

glTranslatef(ship.position);
vector axis;
float angle;
ship.orientation.quaternionToAxisAngle(&axis, &angle);
glRotatef(angle, axis.x, axis.y, axis.z);
//render the object here

How''s that?
For nice, smooth camera control with quaternions, look up articles on quaternion interpolation, also called slerp. There was also an interesting article in the Game Programming Gems book about a quaternion "shortest rotation arc" or something like that, I found it quite useful.

##### Share on other sites
first of all thanks everyone for the input ...

Now, I know you're gonna call me lazy (it's getting late here, and i'm determined to crack this tonight!) but assume for example i'm flying through a 3d scene (ie moving the camera around), but so far the above only deals with rotating the camera around a fixed point ... what about allowing it full movement as in a normal flight sim? how do you work out where the ship/aeroplane will be after a given rotation, at a given forward velocity? The reason i'm asking is because if you know the start vector ... and say you travel at 1 km per second ... you won't be 1 km further away after a second, because you'll have described an arc through whatever medium you're flying! HELP ...

for those that are interested i'm trying to incorporate some form of prediction into the engine i'm creating, so as to allow internet play without being dependant on a good ping ... i'm therefore gonna have to be able to take a know position and rotation and predict the next few probable positions over a given amount of time. say for example another player is banking fully to the right, whilst climbing at the maximum rate, it must be assumed (in the case of a momentarily lost connection) that they are still performing that move!

Please keep this one going, as it is proving to be quite an interesting discussion! I'm sure a lot of ppl will benefit from understanding quaternions!!!

Many Regards All

(PS try http://personal.nbnet.nb.ca/daveg/opengl/quatdemo/quatdemo.zip it's an interesting example of quaternions)

Edited by - Shag on July 17, 2001 9:42:43 PM

##### Share on other sites
quote:
Original post by Shag
The reason i''m asking is because if you know the start vector ... and say you travel at 1 km per second ... you won''t be 1 km further away after a second, because you''ll have described an arc through whatever medium you''re flying! HELP ...

NewDeal posted some equations to get the vector of the camera based on its orientation....

dirX = 2.0 * (x * z - w * y)
dirY = 2.0 * (y * z + w * x)
dirZ = 1.0 - 2.0 * (x * x + y * y);

(x,y,z,w are parts of a Quaternion)

I''m not sure if that''s what you want though.

My thanks goes out to all of you too. NewDeal, I''ve managed to break your class somehow =). I''ve never met a piece of code I couldn''t make work anymore, and well, yours is no exception. Here''s a code snippit:

tempquat.EulerToQuat(pyaw, ppitch, proll); //praw etc are amounts gotten by keyboard input
tempquat.MultQuat(rotquat); //rotquat = rotation quaternion. RotQuat. Thats a damn good variable name.
tempquat.toAxisAngle(result);
rotquat->x = tempquat->x;//Need to overload + for this
rotquat->y = tempquat->y;
rotquat->z = tempquat->z;
rotquat->w = tempquat->w;
rotquat->qLength = tempquat->qlength;
glRotatef(result[0], result[1], result[2], result[3]);

This is done using NewDeal''s Quat Class. For some reason all I see is my skybox flickering in and out of existance, and if I hit a key (make pyaw, ppitch, or proll different from 0 for 1 frame) everything disappears entirely.

##### Share on other sites
Oops, forgot to login. The post above is mine.

##### Share on other sites
Umm... I''m not sure what quaternion rotation has to do with the width of your skybox, are you sure you don''t have your classes mixed up or something?

-David-

##### Share on other sites
quote:
Original post by Shag
first of all thanks everyone for the input ...

no prob...
quote:
Original post by Shag
Now, I know you''re gonna call me lazy

ok, lazy
quote:
Original post by Shag
(it''s getting late here, and i''m determined to crack this tonight!)

Not likely! (Just being realistic...)
quote:
Original post by Shag
but assume for example i''m flying through a 3d scene (ie moving the camera around), but so far the above only deals with rotating the camera around a fixed point ... what about allowing it full movement as in a normal flight sim? how do you work out where the ship/aeroplane will be after a given rotation, at a given forward velocity? The reason i''m asking is because if you know the start vector ... and say you travel at 1 km per second ... you won''t be 1 km further away after a second, because you''ll have described an arc through whatever medium you''re flying! HELP ...

to do the movement along an arc you''ll have to use finner time slices. The smaller time slice you use the smother the arc. if for example you move 1 km and bank 10 degrees in 1 second you could divide that into 20 updates of 0.5 degrees bank and 0.05km of movement that would give you a 20 sided arc not a perfect arc but smother that just a straight line. To get a smoth movement you''ll probably have to eather use a spline curve or possably that smoth interpolation in the game programming gems book that Dobbs mentioned (I gotta get that now)

Also, anyone that actually understands the actuall quaternion math stuff (not just how to use it) I''d be interested in working on a tutorial that explains quaternions that we could maybe get nehe to put on the site? Anyway I''m gonna start working on it myself anyone that wants to help e-mail me at avian@prairie.lakes.com

##### Share on other sites
Ok Dave

Your code looks very much like mine (which works) so i dont think the problem lies in the code you just posted.

Please take no offense but ill list some things you might havent thought of .

First of all try letting go of the skybox for a while (while testing the other stuff). Put in a box or sumthing and try moving around it.

Make sure that pyaw, ppitch, proll are containing only the values for last frame. I set them to 0 when im done rotating. And make sure that they are in radians (very important and i dont think i mentioned it).

When you create the RotQuat use the constructor which takes no parameters. Its important that w is set to 1 initialy since this is the identity quat for multiplications.

Try normalizing both quats after each frame. Dont think this is the problem but it cant hurt.

Good luck.

BTW if you want my entire camera class then feel free to email me.

##### Share on other sites
Have a look at:
http://www.btinternet.com/~matt.lisa/ogl1.htm
It helped me out!

##### Share on other sites
COOL it''s all working!!! quaternions are easy ... it''s official!

Thanks to everyone how has posted here ...

BTW ... if anyone is interested here are a couple of screen shots of the earth, with specular reflections of the oceans, land mass, and cloud cover!

http://www.btinternet.com/~mark.shaxted/

##### Share on other sites
Thanks for all your help, I got my Quats working as well. As it turns out, everything with my code was sound. This was the problem: I had a function called deg2rad which converted degrees to radians (so I could use degrees with the trig functions). Unbeknownst to me, the vile Coding Gnomes turned on my computer during the night, and changed return blah*(PI/180.0) to return blah*(PI*180.0). Those bastards.

##### Share on other sites
quote:
Original post by Shag
BTW ... if anyone is interested here are a couple of screen shots of the earth, with specular reflections of the oceans, land mass, and cloud cover!

http://www.btinternet.com/~mark.shaxted/

No fair...your skybox looks better than mine .

##### Share on other sites
LOL Dave ... i knicked the skybox off someone else''s site ... for development purposes only (ahem)...

BTW ... got any shots yourself?

also ... check out www.dodgyposse.com ... exactly what we''re all trying not to do ... hmmmmm ... although it is an interesting project to gauge against!

##### Share on other sites
Well, here''s the screenshot, but its not much to look at, no objects yet. Just one massive skybox. Atleast IT works just like its suppose to.

http://clanbore.hobbiton.org/mwuahaha.png