OrangeMan
OrangeMan

Reputation: 692

Rotate a model with a quaternion

I have found so may solutions for this problem yet none seem to work.

I am using the JBullet library and retrieving an objects orientation and it is given as a quaternion. How would I retrieve the Euler values from this quaternion so I could call..?

glRotate(rotationX, 1, 0, 0);
glRotate(rotationY, 0, 1, 0);
glRotate(rotationZ, 0, 0, 1);

Or maybe there is a more efficient way?

EDIT:

I have tried quat -> vec

public static Vector3f quatToVec(Quat4f q) {
        float x = q.x;
        float y = q.y;
        float z = q.z;
        float w = q.w;
        float roll  = (float) (Math.atan2(2*y*w - 2*x*z, 1 - 2*y*y - 2*z*z) / Math.PI * 360);
        float pitch = (float) (Math.atan2(2*x*w - 2*y*z, 1 - 2*x*x - 2*z*z) / Math.PI * 360);
        float yaw   =  (float) (Math.asin(2*x*y + 2*z*w) / Math.PI * 720);
        return new Vector3f(yaw, pitch, roll);
    }

I have tried quat -> rotation matrix

public static FloatBuffer quatToMatrix(Quat4f q) {
        float qx = q.x;
        float qy = q.y;
        float qz = q.z;
        float qw = q.w;
        FloatBuffer fb = BufferUtils.createFloatBuffer(16);
        fb.put(new float[]{1.0f - 2.0f*qy*qy - 2.0f*qz*qz, 2.0f*qx*qy - 2.0f*qz*qw, 2.0f*qx*qz + 2.0f*qy*qw, 0.0f,
                2.0f*qx*qy + 2.0f*qz*qw, 1.0f - 2.0f*qx*qx - 2.0f*qz*qz, 2.0f*qy*qz - 2.0f*qx*qw, 0.0f,
                2.0f*qx*qz - 2.0f*qy*qw, 2.0f*qy*qz + 2.0f*qx*qw, 1.0f - 2.0f*qx*qx - 2.0f*qy*qy, 0.0f,
                0.0f, 0.0f, 0.0f, 1.0f});
        fb.flip();
        return fb;
    }

Yet none of it seems to work

Upvotes: 0

Views: 235

Answers (3)

Andon M. Coleman
Andon M. Coleman

Reputation: 43319

The second solution you posted is preferable, because Euler angles suffer from singularities (known as gimbal lock in other fields) at +/- 90 degrees pitch.

Your biggest obstacle right now is that your matrix is row-major for whatever reason. Since this is a generic FloatBuffer and not an actual matrix class, you will probably have to transpose the matrix yourself when you do fb.put (...).

This should do the trick:

fb.put(new float[] {1.0f - 2.0f*qy*qy - 2.0f*qz*qz, 2.0f*qx*qy + 2.0f*qz*qw,        2.0f*qx*qz - 2.0f*qy*qw,        0.0f,
                    2.0f*qx*qy - 2.0f*qz*qw,        1.0f - 2.0f*qx*qx - 2.0f*qz*qz, 2.0f*qy*qz + 2.0f*qx*qw,        0.0f,
                    2.0f*qx*qz + 2.0f*qy*qw,        2.0f*qy*qz - 2.0f*qx*qw,        1.0f - 2.0f*qx*qx - 2.0f*qy*qy, 0.0f,
                    0.0f,                           0.0f,                           0.0f,                           1.0f});

Upvotes: 2

Kent
Kent

Reputation: 743

I've had this problem before, here is my (directly copy-pasted) code:

    static public void addBoneRotation(float[] quart){
    //0  1  2  3   4   5   6
    //x, y, z, qw, qx, qy, qz;

    //rotate by (qw, qx, qy, qz)
    tmp.m00=1 - 2*quart[5]*quart[5] - 2*quart[6]*quart[6];
    tmp.m01=2*quart[4]*quart[5] - 2*quart[6]*quart[3];
    tmp.m02=2*quart[4]*quart[6] + 2*quart[5]*quart[3];
    tmp.m03=0;
    tmp.m10=2*quart[4]*quart[5] + 2*quart[6]*quart[3];
    tmp.m11=1 - 2*quart[4]*quart[4] - 2*quart[6]*quart[6];
    tmp.m12=2*quart[5]*quart[6] - 2*quart[4]*quart[3];
    tmp.m13=0;
    tmp.m20=2*quart[4]*quart[6] - 2*quart[5]*quart[3];
    tmp.m21=2*quart[5]*quart[6] + 2*quart[4]*quart[3];
    tmp.m22=1 - 2*quart[4]*quart[4] - 2*quart[5]*quart[5];
    tmp.m23=0;
    tmp.m30=tmp.m31=tmp.m32=0;
    tmp.m33=1;

    //translate by (x,y,z)
    tmp2.m30=quart[0];
    tmp2.m31=quart[1];
    tmp2.m32=quart[2];

    Matrix4f.mul(tmp2,tmp,tmp);
    //add to the current bone transformation
    Matrix4f.mul(tmp, bone, bone);
}

this assumes quart[] holds a bone translation and rotation.

you will need to change this a bit to match your application.

allows a succession of these calls to chain bones together.

Upvotes: 1

ratchet freak
ratchet freak

Reputation: 48196

you can go with 1 rotate call using

glRotation(Math.acos(q.w)*360/Math.PI, q.x, q.y, q.z);

however the matrix extraction is preferable, because it avoids the acos and then the cos inside the glRotation call

Upvotes: 2

Related Questions