四元数旋转,试图围绕轴旋转物体

时间:2014-07-10 16:13:26

标签: opengl math rotation quaternions euler-angles

我在Opengl中显示caracters,我让它们围绕轴旋转四元数,我想要实现的是让它们围绕自己的轴旋转但是当使用四元数时,如果我按照一个斧头旋转一个物体,其他人不要考虑到这种旋转将围绕固定世界轴旋转。 给定四元数Qaccumulative(前旋转)和3个角度AngleX,AngleY和AngleZ。 首先我认为欧拉的轮换是尝试的东西,我尝试了几种技术:

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

到目前为止,他们都没有工作......我不认为我的旋转实现是问题,但如果有人,我会发布代码。 Euler不是我认为的吗?我应该用什么样的轮换来实现我的目标?

编辑:我试过这个,帖子建议:

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

角色仍围绕固定轴旋转。

编辑: 我应用了一个帖子给出的伪代码,它起作用了:

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 个答案:

答案 0 :(得分: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

例如,如果你想应用一个&#39; roll&#39;旋转角度为45个单位(度数或弧度取决于你的旋转方法)到你的角色:

enter image description here

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