3
votes

I display caracters in Opengl, i have them rotate around axis with quaternions, what i want to achieve is make them rotate around their own axis but when using quaternions, if i rotate an object according to one axe, the others don't take in consideration this rotation will rotate around a fix world axe. Given a Quaternion Qaccumulative (former rotations) and 3 angles AngleX, AngleY and AngleZ. First i thought Euler's rotation was the thing to try and i tried several techniques :

Quaternion rot1;
Quaternion rot2;
Quaternion rot3;
Vector3 axis ;
float angle;
QAccumulative.getAxisAngle(&axis, &angle);

// first try : around fix axes
    cout << "axis : " << axis << endl;
    rot1.FromAxis(Vector3(1.0,0.0,0.0),angleX);
    rot2.FromAxis(Vector3(0.0,1.0,0.0),angleY);
    rot3.FromAxis(Vector3(0.0,0.0,1.0),angleZ);
    QAccumulative = QAccumulative * rot1;
    QAccumulative = QAccumulative * rot2;
    QAccumulative = QAccumulative * rot3;


/*
// second try, around current modified axes
    rot1.FromAxis(Vector3(axis.x,0.0,0.0),angleX);
    rot2.FromAxis(Vector3(0.0,axis.y,0.0),angleY);
    rot3.FromAxis(Vector3(0.0,0.0,axis.z),angleZ);
    QAccumulative = QAccumulative * rot1;
    QAccumulative = QAccumulative * rot2;
    QAccumulative = QAccumulative * rot3;

*/
/*
// third try with Euler rotation
    Quaternion rotation;
    rotation.FromEuler(10*angleX,10*angleY,10*angleZ);
    QAccumulative = QAccumulative * rotation;
*/
    QAccumulative.normalise();

None of them have worked so far...i don't think my implementations of rotations are the problems but if someone does i will post the code. Isn't Euler what i thought it was ? What can of rotation should i use to achieve my goal ?

EDIT : i have tried this, suggested by a post :

rotate(float angleX,float angleY,float angleZ) {
    Vector3 axis = Vector3(angleX,angleY,angleZ);
    Vector3 worldAxis = QAccumulative * axis;  
    Quaternion worldRotation( worldAxis.x,worldAxis.y,worldAxis.z, 10 );        
    QAccumulative = worldRotation * QAccumulative;
    QAccumulative.normalise();

The character still rotates around fix axis.

EDIT : I applied the pseudo code given by a post and it worked :

rotate(float angleX,float angleY,float angleZ) {
    Vector3 axis = Vector3(angleX,angleY,angleZ);
    Vector3 worldAxis = QAccumulative * axis;  
    Quaternion worldRotationx( 1.0,0,0, angleZ );    
    Quaternion worldRotationy( 0,1.0,0, angleX);        
    Quaternion worldRotationz( 0,0,1.0, -angleY );        
    QAccumulative = worldRotationx * worldRotationy * worldRotationz * QAccumulative;
    QAccumulative.normalise();
1
Are you saying you want to be able to rotate the character around an axis in its local coordinate system, using quaternions?kbirk
Yes exactly in the case of a caracter or a plane i want it to rotate in a coherent way if you see what i mean (local coordinate system seems to be the right expression).aze

1 Answers

2
votes

My first suggestion would be to not define your Quaternion rotation using Euler angles:

Here are some links that explain it better than I can:

http://bitsquid.blogspot.ca/2013/03/what-is-gimbal-lock-and-why-do-we-still.html

https://mathoverflow.net/questions/95902/the-gimbal-lock-shows-up-in-my-quaternions

http://answers.unity3d.com/questions/573035/avoiding-gimbal-lock.html

I recommend defining your rotations as a single axis and angle and writing your class interface to follow that, here are some suggestions:

Vector3 operator* ( const Vector3& vec ) const;        // rotate a vector
Quaternion operator* ( const Quaternion& quat ) const; // concatenate 
void set( const Vector3& axis, float angle );          // set quaternion
void getAxisAngle( Vector3* axis, float* angle );      // extract axis and angle

As for applying a local axis rotation using quaternions you could simply transform the local axis into world space and apply the transformation that way.

I'm assuming you store the characters transform as a rotation quaternion, translation vector, and scale vector/scalar. In this case you simply apply the characters rotation quaternion to the local axis to bring it into world space, then use that world space axis to build and apply the rotation as you normally would.

You have your characters current rotation stored as a quaternion:

Quaternion characterQuaternion;

Then you have the local rotation you want to apply:

Vector3 localAxis;
float angle;

You need to transform the local axis, into world space, then build a quaternion from that and apply it to your characters quaternion:

Vector3 worldAxis = characterQuaternion * localAxis;       // transform local axis to world coordinate system   
Quaternion worldRotation( worldAxis, angle );              // build quaternion   
characterQuaternion = worldRotation * characterQuaternion; // apply the rotation

For example, if you wanted to apply a 'roll' rotation of with an angle of 45 units (degree or radian depending on your rotation methods ) to your character:

enter image description here

localAxis = Vector3(1,0,0);
angle = 45;