Opengl 四元数旋转,尝试绕其轴旋转对象

Opengl 四元数旋转,尝试绕其轴旋转对象,opengl,math,rotation,quaternions,euler-angles,Opengl,Math,Rotation,Quaternions,Euler Angles,我在Opengl中显示角色,我让它们用四元数绕轴旋转,我想实现的是让它们绕自己的轴旋转,但在使用四元数时,如果我根据一个轴旋转对象,其他人不会考虑此旋转将绕固定世界轴旋转。 给定一个四元数Q累加(以前的旋转)和3个角度AngleX、AngleY和AngleZ。 首先,我认为欧拉的旋转是值得尝试的,我尝试了几种技巧: Quaternion rot1; Quaternion rot2; Quaternion rot3; Vector3 axis ; float angle; QAccumulativ

我在Opengl中显示角色,我让它们用四元数绕轴旋转,我想实现的是让它们绕自己的轴旋转,但在使用四元数时,如果我根据一个轴旋转对象,其他人不会考虑此旋转将绕固定世界轴旋转。 给定一个四元数Q累加(以前的旋转)和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 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();

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

以下是一些比我能更好地解释它的链接:

我建议将旋转定义为一个轴和角度,然后编写类接口,如下所示:

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 worldAxis = characterQuaternion * localAxis;       // transform local axis to world coordinate system   
Quaternion worldRotation( worldAxis, angle );              // build quaternion   
characterQuaternion = worldRotation * characterQuaternion; // apply the rotation
然后,就有了要应用的局部旋转:

Vector3 localAxis;
float angle;
您需要将局部轴变换为世界空间,然后从该轴构建四元数,并将其应用于角色四元数:

Quaternion characterQuaternion;
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;


你是说你想使用四元数在局部坐标系中绕轴旋转角色?是的,对于角色或平面,如果你明白我的意思,我希望它以连贯的方式旋转(局部坐标系似乎是正确的表达式)。我应该在哪里使用我的新参数:angleX,安格利和安格利兹?或者我应该在我上面描述的某个技巧之后做什么?对不起,我没有很好地指定我的程序条目,我在介绍中添加了一句话。我已经编辑了我的回答。基本上,您应该尽量避免使用Euler角度,因为它们容易发生万向节锁定。感谢有关Euler的信息,我认为这是一个有效的选项,但根据您的建议,我不明白何时应用新旋转,characterQuaternion是我的Qaccumulative,localAxis对应于Qacc.getAxisAngle(),因此,我在哪里添加我的新角度?一定有什么我没有从你的帖子中得到。你的四元数类应该包括以下功能:旋转一个向量(我使用操作符*),连接另一个四元数(我也使用操作符*),以及从轴和角度构建一个四元数(我使用构造函数)。