Palindrom
Palindrom

Reputation: 443

Quaternion to axis angles

I try to implement 3D object rotations according data taken from sensor. I have data as quaternions w,x,y,z but to use

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

I need rotation angles across x,y,z to obtain these with this tutorial and QQuaternion in Qt IDE I write below code:

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;
    }
}

However, when I rotate with above code, movements are not correct, directions are different and also even sensor move 90 degrees to left it move so much little to another direction.

When I search about quaternion and openGL, some gives advice about rotation could be done on camera on openGL by using glMultMatrixf(quaternion.toMatrix) but I could not convert quaternion to a matrix GLFloat which is requested as parameter in glMultMatrixf. QQuaternion class cloud convert quaternion to QVector4D and gives error variable casting. Maybe the way did is wrong which is below code:

    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 

To sum, how can i solve the issue with these quaternions for interpreting rotations on an object with openGL ?

Upvotes: 3

Views: 9068

Answers (2)

Palindrom
Palindrom

Reputation: 443

I try out some other methods for implementation.I directly convert quaternions to X Y Z axis angles. I hope it will be useful for others also:

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

Upvotes: 1

ratchet freak
ratchet freak

Reputation: 48216

You shouldn't convert to axis angle, instead create the rotation matrix directly and use glMultMatrix.

converting a quaternion to matrix can be done with the following: (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;
}

You can then use the constData member to pass into multMatrix:

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

Upvotes: 1

Related Questions