Jump to content
  • Advertisement

Archived

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

Dave the Embalmer

Quaternions: A Real Pisser

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

If you intended to correct an error in the post then please contact us.

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 this post


Link to post
Share on other sites
Advertisement
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!