四元数旋转,尝试围绕其轴旋转一个物体

3

我在Opengl中展示字符,我使用四元数将它们绕轴旋转,我想实现的是让它们绕自己的轴旋转,但是当使用四元数时,如果我根据一个轴旋转对象,其他轴不会考虑这个旋转将绕固定的世界轴旋转。 给定一个四元数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();

迄今为止,它们都没有起作用......我不认为我的旋转实现有问题,但如果有人发现我会发布代码。欧拉不是我想象中的那样吗?我应该使用什么类型的旋转来实现我的目标?
编辑:我已经尝试过这个建议帖子中提到的方法:
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();

你是说你想使用四元数将字符围绕其局部坐标系中的轴旋转? - kbirk
是的,确切地说,对于一个字符或平面,我希望它在旋转时有一个连贯的方式,如果你知道我的意思(局部坐标系似乎是正确的表达)。 - aze
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个单位(度或弧度取决于您的旋转方法):

enter image description here

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

我应该在哪里使用我的新参数:angleX,angleY和angleZ?还是我应该按照我上面描述的技术之一做你所说的? - aze
抱歉,我没有很好地指定我的程序条目,我在介绍中添加了一句话。 - aze
我已经编辑了我的回答。基本上,你应该尽量避免使用欧拉角,因为它们容易发生万向锁问题。 - kbirk
感谢您提供有关欧拉角的信息,我认为这是一个有效的选择,但根据您的建议,我不明白何时应用新的旋转。characterQuaternion是我的Qaccumulative,localAxis对应于Qacc.getAxisAngle(),因此我应该在哪里添加新的角度?您的帖子中一定有我没有理解的地方。 - aze
你的四元数类应该包括以下功能:旋转向量(我使用operator实现),与另一个四元数连接(我同样使用operator实现),以及通过轴和角度构建四元数(我使用构造函数实现)。 - kbirk
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接