3

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 ?

1
  • This seems to be an XY problem, The question asks about a specific conversion, but the answer may be a different use of OpenGL - meta.stackexchange.com/questions/66377 Commented Apr 4, 2015 at 3:36

2 Answers 2

1

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());
Sign up to request clarification or add additional context in comments.

4 Comments

Does it return 4x4 matrix ? can I use it with glMulMatrix(result); ?
the return value is a QMatrix4x4 the constData member will return a pointer that you can pass into glMultMatrix
I miss some point I guess.. I write glMultMatrix(rotatedMat); at the very beginning of the code -before draw the object- and after that, I calculate quaternion result matrix4x4 (as yoru previous code) and call method "void setRotatedMat(QMatrix4x4 qmat) { rotatedMat=qmat; }" but it give error as "no matching function for call to glMultMatrix" and also "no known conversion from QMatrix4x4 to const GLfloat *m" --- I update my question code for better understanding
Errors are solved but I could not rotate object.. I took around 16000 data and using quattomat change them to mat but even if using constdata it will not move-- I update my paintGL func.
1

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

3 Comments

You may want to check against divide-by-zero here, (last 3 lines), also, you could assign sin(acos(q0)) to a variable, on the off chance the 2x additional calls aren't optimized out.
Please could somebody explain what q0Buffer.at(i) etc does. I assume it does something with the quaternion.
q0Buffer, is a vector by size 4 that includes quartenion elemts, q0Buffer.at(i) is pretty much as same as q0Buffer[i]. .at(i) is the optimised way to read from a vector. More info thispointer.com/…

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.