3

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();
4

1 回答 1

2

我的第一个建议是不要使用欧拉角定义你的四元数旋转:

这里有一些链接比我能更好地解释它:

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

我建议将您的旋转定义为单个轴和角度,并编写您的类接口来遵循它,这里有一些建议:

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

至于使用四元数应用局部轴旋转,您可以简单地将局部轴转换为世界空间并以这种方式应用转换。

我假设您将字符变换存储为旋转四元数、平移向量和缩放向量/标量。在这种情况下,您只需将角色旋转四元数应用于局部轴以将其带入世界空间,然后使用该世界空间轴像往常一样构建和应用旋转。

您将角色当前旋转存储为四元数:

Quaternion characterQuaternion;

然后你有你想要应用的本地轮换:

Vector3 localAxis;
float angle;

您需要将局部轴转换为世界空间,然后从中构建一个四元数并将其应用于您的角色四元数:

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

例如,如果您想对角色应用角度为 45 个单位(度数或弧度,取决于您的旋转方法)的“滚动”旋转:

在此处输入图像描述

localAxis = Vector3(1,0,0);
angle = 45;
于 2014-07-10T18:19:53.230 回答