Rotating around a Pivotpoint with Quaternions

C87f04d6d4017ed62e75487bc8c06335
0
Jan 101 Nov 25, 2005 at 11:32

Hi there

Ok, the situation is as follows: I have a mesh and want to animate it. Up to now i have used relative rotations and translations at every bone to construct a bone-matrix, which incorporates the whole transformation at a given bone.

Since current GPUs (Radeon 9700) are not able to store enough bone-matrices for my purposes, i want to switch from matrices (16 values per bone) to quaternions and a translation vector (4 values for the quaternion, 3 for the tanslation = 7 values).

Now i need to compute my final quaternion/translation stuff to send it to the GPU. However, when using matrices i had no problem to rotate around a certain point. I first translated that point to 0, then rotated, then translated it back. All that can, of course, be put into one final matrix.

But how do i do that with quaternions??? Certainly i need to modify my translation-vector for that bone, so that after the rotation by the quaternion, the vertex then gets translated to the point where it was supposed to be rotated around.

I just can’t figure out the maths, how to achieve this, at the moment.

Would be nice, if someone could enlighten me :lol:

Thanks,
Jan.

4 Replies

Please log in or register to post a reply.

340bf64ac6abda6e40f7e860279823cb
0
_oisyn 101 Nov 25, 2005 at 12:09

It’s handy to just write down what you’re doing when rotating about an arbitraty point P with a matrix.

First, we need to get P at the origin, so we translate with -P. Then we rotate with R, and then reapply the translation P. The matrix equation (when using row vectors as in D3D) therefore is MP-1 * MR * MP. As you need a transformation in the form rotation*translation, we need to reverse the order of MP-1 * MR, so we get MR * A = MP-1 * MR.

Calculating A is simple: as the final expression should read MP-1 * MR, and we start with MR * A, we can cancel out the first MR transformation by multiplying with MR-1, which yields the identity matrix, and then multiply with the original expression we are looking for: MP-1 * MR. Therefore, A = MR-1 * MP-1 * MR, which will always yield a simple translation matrix around the point -P * MR.

Fill that in the final equation, and the translation vector you’re looking for is (-P * MR) + P

340bf64ac6abda6e40f7e860279823cb
0
_oisyn 101 Nov 25, 2005 at 12:16

BTW, you don’t specifically need a quaternion to bring the number of values back to 7. A transformation matrix consist of the secification of 3 axes and a translation. Since the axes are orthogonal, you’ll only need 2 as you can calculate the third one using the crossproduct of the first two. And since every axis is of length 1, you’ll need 2 floats per axis (z = sqrt(1 - x2 - y2). So 2 axes of 2 floats per axis, and a translation totals 2 * 2 + 3 = 7 floats :)

Of course, you’ll need only 3 values per quaternion as the quaternion also is always of length 1.

E0613df9e198a3ebbad23b02b714eb42
0
ikk 101 Nov 25, 2005 at 13:31

hello,
if you’re using directx maybe this code ll help you. this is what im using in my project to rotate actor around specified point by quaternion and move by specified vector.
mat variable is D3DXMATRIX type and qRot is D3DXQUATERNION type, both are class members.

// DESC: modifies position and quaternion. does not set it, to set, first zero out 
//       actor position and or movement before call to this method or set 'bSet' to
//       true.
// lpvMovement - 
// lpqRotation - 
// lpvRotOrig  - origin of rotation, this param is ignored if 'lpqRotation' is null.
//               also if this param is null and rotation is requested then rotation is
//               done around actor origin.
// bSet        - if true then position and rotation are set, not modified.
VOID CActor::
ModifyVecsPosQuat( const D3DXVECTOR3* lpvMovement, const D3DXQUATERNION* lpqRotation,
                  const D3DXVECTOR3* lpvRotOrig, BYTE bSet )
{
    if(bSet){
        D3DXMatrixIdentity( &mat );
        D3DXQuaternionIdentity( &qRot ); 
        D3DXQuaternionNormalize( &qRot, &qRot );    //hmmm..
    }
    D3DXMATRIX m;
    if( lpqRotation ){
        if( lpvRotOrig ){
            // translate by point -p, that is, by negation of rotation origin
            D3DXVECTOR3 vNeg = -(*lpvRotOrig);
            D3DXMatrixTranslation( &m, vNeg.x, vNeg.y, vNeg.z );
            mat *= m;
        }
        // do rotation
        D3DXMatrixRotationQuaternion( &m, lpqRotation );
        mat    *= m;
        qRot   *= *lpqRotation;
        if( lpvRotOrig ){
            // translate by p, rotation origin
            D3DXMatrixTranslation( &m, lpvRotOrig->x, lpvRotOrig->y, lpvRotOrig->z );
            mat *= m;
        }
    }
    if( lpvMovement ){
        D3DXMatrixTranslation( &m, lpvMovement->x, lpvMovement->y, lpvMovement->z );
        mat *= m;
    }
    OnPositionOrientationChange();
}

also, in directx, helpful functions while doing rotation are:
D3DXMatrixRotationQuaternion - Builds a rotation matrix from a quaternion,
D3DXQuaternionRotationMatrix - Builds a quaternion from a rotation matrix

C87f04d6d4017ed62e75487bc8c06335
0
Jan 101 Nov 25, 2005 at 16:54

Great, thanks, tomorrow i will try it again. :yes: