四元数到轴的角度

时间:2015-03-24 10:01:51

标签: c++ qt opengl rotation quaternions

我尝试根据从传感器获取的数据实现3D对象旋转。我有数据作为四元数w,x,y,z但是要使用

   glRotatef(xRot,1,0,0);
   glRotatef(yRot,0,1,0);
   glRotatef(zRot,0,0,1);

我需要跨越x,y,z的旋转角度,以便在Qt IDE中使用this教程和QQuaternion获取这些,我在下面编写代码:

void quaternion2angle(float w,float x,float y,float z)
{
    // Code for quaternion to rotation around axis X Y Z
    QQuaternion ql;
    ql.setScalar(w);
    ql.setX(x);
    ql.setY(y);
    ql.setZ(z);

    if (ql.scalar()>1) ql.normalize();
    angle= 2 * acos(ql.scalar());
    s= sqrt(1-ql.scalar()*ql.scalar());
    if (s<0.001) {
        xRot=ql.x();
        yRot=ql.y();
        zRot=ql.z();
    }else
    {
        xRot=ql.x()/s;
        yRot=ql.y()/s;
        zRot=ql.y()/s;
    }
}

然而,当我使用上面的代码旋转时,动作不正确,方向不同,甚至传感器向左移动90度,它向另一个方向移动很少。

当我搜索四元数和openGL时,有些人提出了关于旋转的建议可以通过使用glMultMatrixf(quaternion.toMatrix)在openGL上的相机上完成,但我无法将四元数转换为矩阵GLFloat,它是glMultMatrixf中作为参数请求的。 QQuaternion类云将四元数转换为QVector4D并提供错误变量转换。也许这样做的方式是错误的,低于代码:

    void paintGL()
         {
          glEnable(GL_DEPTH_TEST);
          glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
          glLoadIdentity();
       // adjust camera
          glTranslatef(0.0f, 0.0f, -8.0f);
          glMultMatrixf(quMatrix.constData());
          glRotatef(90,0,1,0);

       // no need below
         //glRotatef(xRot,1,0,0);
         //glRotatef(yRot,0,1,0);
         //glRotatef(zRot,0,0,1);


         obj.Draw();
         glDisable(GL_DEPTH_TEST);
         }

    void setquMatrix(QVector4D qvec)
        {
        // read data w,x,y,z
        qvec=quaternionRotation(w,x,y,z);
        quMatrix=qvec;
        }

    // Using quaternion and glMultMatrixf
    QVector4D quaternionRotation(float w,float x,float y,float z)
        {
            QQuaternion qlm;
            qlm.setScalar(w);
            qlm.setX(x);
            qlm.setY(y);
            qlm.setZ(z);
            qlm.normalize();
            return qlm.toVector4D();
        }
    // after taking value above I set matrix which is multiplied with glMultMatrixf 

总而言之,如何使用这些四元数解决使用openGL解释对象旋转的问题?

2 个答案:

答案 0 :(得分:1)

您不应该转换为轴角,而是直接创建旋转矩阵并使用glMultMatrix。

将四元数转换为矩阵可以通过以下方式完成:(sourced from my previous code)

inline QMatrix4x4 quatToMat(QQuaternion q)
{
    //based on algorithm on wikipedia
    // http://en.wikipedia.org/wiki/Rotation_matrix#Quaternion
    float w = q.scalar ();
    float x = q.x();
    float y = q.y();
    float z = q.z();

    float n = q.lengthSquared();
    float s =  n == 0?  0 : 2 / n;
    float wx = s * w * x, wy = s * w * y, wz = s * w * z;
    float xx = s * x * x, xy = s * x * y, xz = s * x * z;
    float yy = s * y * y, yz = s * y * z, zz = s * z * z;

    float m[16] = { 1 - (yy + zz),         xy + wz ,         xz - wy ,0,
                         xy - wz ,    1 - (xx + zz),         yz + wx ,0,
                         xz + wy ,         yz - wx ,    1 - (xx + yy),0,
                               0 ,               0 ,               0 ,1  };
    QMatrix4x4 result =  QMatrix4x4(m,4,4);
    result.optimize ();
    return result;
}

然后,您可以使用constData成员传递到multMatrix:

QMatrix4x4 rotation = quatToMat(quat);
glMultMatrix(rotation.constData());

答案 1 :(得分:1)

我尝试了其他一些实现方法。我直接将四元数转换为X Y Z轴角度。我希望它对其他人也有用:

    float q0 = q0Buffer.at(i);
    float q1 = q1Buffer.at(i);
    float q2 = q2Buffer.at(i);
    float q3 = q3Buffer.at(i);

    float angle_rad = acos(q0) * 2;
    float angle_deg = angle_rad * 180 / PI;
    float x = q1 / sin(angle_rad/2);
    float y = q2 / sin(angle_rad/2);
    float z = q3 / sin(angle_rad/2);