# Combining Rotation Matricies

Hello,
This question is probably for Mike Lischke only but if anyone has any idea let me know.  Ta

I would like to combine a rotation matrix to do one rotation in one direction then another rotation in another direction.  The problem im having is that in Mike's "opener" code, it rotates an object (to translate from .3ds) to a certain position. If I want to rotate it again in a diferent direction is combines the previous rotation and gives me strange results.  So I need to do one rotation at the very start (say on the X) then all rotations after that on the Y. Is that impossible?

I found a function called QuaternionMultiply in geomtry.pas which sounds like it should do the trick but I haven't a clue how to use it.

I really hope the above made sense.

Cheers
Woody.
###### Who is Participating?

Commented:
No, this will not work:

// open the door
Matrix2 := CreateRotationMatrix(MakeAffineVector([RotX, RotY, RotZ]), 1);
Matrix := MatrixMultiply(Matrix, Matrix2);

The reason is that RotX, Y, Z are angles not an axis. You could use here three calls like:

// open the door
Matrix2 := CreateRotationMatrix(MakeAffineVector([1, 0, 0]), RotX);
Matrix := MatrixMultiply(Matrix, Matrix2);

etc. or you simply use:

Matrix := Pitch(Matrix, RotX);
Matrix := Turn(Matrix, RotY);
Matrix := Roll(Matrix, RotZ);

Note that this is the kind of Euler angles rotation I talked above which may sometimes not give the requested result. To avoid this you need to use the overloaded variant of these functions and provide a vector (which is usually one of the world axes: [1, 0, 0], [0, 1, 0] and [0, 0, 1]). This is a difference because after the Pitch call the objects up vector no longer is aligned to [0, 1, 0] and turning around this axis is totally different than around the world's "up" vector.

Ciao, Mike
0

Commented:
Hi Woody,

well, usually the results aren't that what one would expect when using Euler angles (that is, to describe a free rotation by applying three "base" rotations about X, Y and Z). Quaternions are not bad but their main advantage lie in the animation field where you may need to smoothly rotate an object about an arbitrary axis and spin it possibly at the same time.

For your problem I would recommend another approach. Look into Geometry.pas. There are 6 functions to roll, turn and pitch a coordinate system around an arbitrary axis.

Ciao, Mike
0

Author Commented:
I have spit the code to treat ever object contaioned in the 3ds file as sperate objects so I can spin individual objects independantly.  When I apply a rotation matrix around the X to an object that has already been rotated on the Y I get the combination of both rotations, which is not what I want.  After the whole scene has been imported to the viewer, I just want all object to rotate in one direction and forget about all rotations that were applied during the import process.  I now store an objects current matrix but I seem to lose the pivot point, so I've reverted back to calculating the objects position from the original matrix.

Will the functions you have mentioned work in this way?

How do I use the MakeQuaternion funtion?

Thanks
0

Commented:
No, the functions I mentioned add another rotation to what was before. This is how rotation actually works mostly. But I'm thinking now about another way for you. Since you are interested to take back all rotations which have been made while importing the objects you can probably decompose the resulting object matrix (see MatrixDecompose in Geometry.pas) and create a rotation matrix from the returned values. Invert this matrix then and apply it to the object matrix. So you should get the unrotated object.

For quaternion operations I recommend that you look for the comp.graphics.algotithms FAQs (news groups or www.faq.org) to learn how to work with them. MakeQuaternion is a simple function to fill a TQuaternion record with the values you provide (or build a quaternion on the fly).

Ciao, Mike
0

Commented:
héhé,
Mike ? Is there something you don't know in programming ?

Woody,
If the result of your rotation is not what you want, it's probably because you don't make the rotation in the right order.

a rotation can be represented by a quaternion rotation and the function
QuaternionMultiply gives the rotation obtained by the composition of the two quaternions given in param...it that's helpfull...

to do a rotation in X then rotations by Y, you create the rotation matrix in X, push it on the stack, multiplie by the rotation matrix in Y, get the matrix pushed on the stack and multiplie it by the new rotation matrix in Y...
0

Commented:
jeurk, of course, there are a lot of things I don't know :-)

Woody, I'm still confused. Let's assume another situation. Say, the image is opend to the right hand side when loaded but want it to be opened to the left hand side (or rotate it down or whatever). Describes this your situation? If yes then my previous recommendations still are valid. You need to take back the rotations already made somehow and then apply your own rotations. What's so difficult with this approach?

Ciao, Mike
0

Commented:
Oops, there's something wrong with E-E. My last comment was sent AFTER your last comment Woody (with the pseudo code). Will E-E never get it right? So many changes in the past month and there's always something unfuctional afterwards... :-(

Ciao, Mike
0

Author Commented:
I've put together some fake code does this look like what you mean ....

Matrix = OriginalPlacedMatrix;
MatrixOnX = CreateRotationMatrixOnX(Matrix);
glPushMatrix;
glMultMatrixf(@MatrixOnX);

MatrixOnY = CreateRotationMatrixOnX(Matrix);
glPushMatrix;
glMultMatrixf(@MatrixOnY);

Just to clarify what I need.

Imagine a house.  The house has a door which is sitting above the door frame.  To place the door in the door frame it needs to be rotated down.  This is it's final position.  I then need to open the door which involves rotating it out.  For each rotation on the door being opened I need to calculate from the point when it was sitting above the door frame.

To rotate on the horizontal axis and then the Vertical axis.

Cheers
Woody.
0

Author Commented:
Err.. very confusing.  Comments all over the place.

I already know the unrotated position so I just need to combine two rotations.  One to get the door to the door frame (vertical).  And another to open the door (horizontal).  I'll post but rotation function shortly.

0

Author Commented:
Ok.  Here is my function.  I'm not even sure which values to pass into the RotX, RotY and RotZ variables!!!

Thanks
John.

//------------------------------------------------------------------------------
// Method:  ManipulateObject
//
// Purpose: Simple method that recompiles the display list based on new object positions.
//------------------------------------------------------------------------------
RecalcPivots, RedrawScene : Boolean; RotX, RotY, RotZ : Single);
Var
Matrix, Matrix2, OrigMatrix : TMatrix;
CurrentMeshIndex : Integer;
NewList : Cardinal;
i : Integer;
MeshIndex : Integer;
Mesh : PMeshObject;
ParentMeshMotion : TKFMesh3DS;
ParentMotionIndex : Integer;
Begin

NewList := glGenLists(1);

glNewList(NewList, GL_COMPILE);

// *******************************************************
// The below section would move the door to the doorframe
// *******************************************************

// consider pivot point (translation simply made...)
Matrix[3, 0] := Matrix[3, 0] - MeshMotion.Pivot.X;
Matrix[3, 1] := Matrix[3, 1] - MeshMotion.Pivot.Y;
Matrix[3, 2] := Matrix[3, 2] - MeshMotion.Pivot.Z;

// scaling
If (MeshMotion.NSKeys > 0) And (MeshMotion.SKeys[0].Time = 0) Then
Begin
Matrix2 := CreateScaleMatrix(TAffineVector(MeshMotion.Scale[0]));
Matrix := MatrixMultiply(Matrix, Matrix2);
End;

// rotation to normal position
If (MeshMotion.NRKeys > 0) And (MeshMotion.RKeys[0].Time = 0) Then
Begin
Matrix2 := CreateRotationMatrix(MakeAffineVector([MeshMotion.Rot[0].X, MeshMotion.Rot[0].Y, MeshMotion.Rot[0].Z]), MeshMotion.Rot[0].Angle);
Matrix := MatrixMultiply(Matrix, Matrix2);
End;

// translation
If (MeshMotion.NPKeys > 0) And (MeshMotion.PKeys[0].Time = 0) Then
Begin
Matrix[3, 0] := Matrix[3, 0] + MeshMotion.Pos[0].X;
Matrix[3, 1] := Matrix[3, 1] + MeshMotion.Pos[0].Y;
Matrix[3, 2] := Matrix[3, 2] + MeshMotion.Pos[0].Z;
End;

While ParentMotionIndex > -1 Do
Begin

// Scalling
Matrix2 := CreateScaleMatrix(TAffineVector(ParentMeshMotion.Scale[0]));
Matrix := MatrixMultiply(Matrix, Matrix2);

// rotation
Matrix2 := CreateRotationMatrix(MakeAffineVector([ParentMeshMotion.Rot[0].X, ParentMeshMotion.Rot[0].Y, ParentMeshMotion.Rot[0].Z]), ParentMeshMotion.Rot[0].Angle);
Matrix := MatrixMultiply(Matrix, Matrix2);

// Translation
Matrix[3, 0] := Matrix[3, 0] + ParentMeshMotion.Pos[0].X;
Matrix[3, 1] := Matrix[3, 1] + ParentMeshMotion.Pos[0].Y;
Matrix[3, 2] := Matrix[3, 2] + ParentMeshMotion.Pos[0].Z;

End;

// *******************************************************
// This is the bit I'm confussed on.
// I need to apply another rotation in another direction (Open the door)
//
// I've provided three variables RotX, RotY, RotZ : Single
//
// I dont want to lose the pivot point either
// *******************************************************

{some code here}

glPushMatrix;
glMultMatrixf(@Matrix);

If Mesh.Visible Then
glCallList(Mesh.ListName);

glPopMatrix;

glEndList;
CheckOpenGLError;

If RedrawScene Then
InvalidateScene;
End;
0

Commented:
Mmh, I think we come closer now. You get wrong results because of the wrong order, I believe. But it is not as Jeurk said but you need to apply the rotation before it is translated! So place the code between

// scaling
If (MeshMotion.NSKeys > 0) And (MeshMotion.SKeys[0].Time = 0) Then
Begin
...
End;

and

// rotation to normal position
If (MeshMotion.NRKeys > 0) And (MeshMotion.RKeys[0].Time = 0) Then
Begin
...
End;

You could also try just to add your angles to the three values of the rotation keys in MeshMotion which are used to create the other rotation matrix. This would save one step.

Ciao, Mike
0

Commented:
No, the last suggestion does not work as there is a quaternion and you have angles. So just make an additional rotation step.

Ciao, Mike
0

Author Commented:
Ok would the below work?

What values do I put in the opening the door rotation?  Can I just use X = 1, y and z = 0?  Or am I just talking crap?

And..  would the below code do the two distinct rotations on X then on Y?

Thanks
Woody.

// consider pivot point (translation simply made...)
Matrix[3, 0] := Matrix[3, 0] - MeshMotion.Pivot.X;
Matrix[3, 1] := Matrix[3, 1] - MeshMotion.Pivot.Y;
Matrix[3, 2] := Matrix[3, 2] - MeshMotion.Pivot.Z;

// scaling
If (MeshMotion.NSKeys > 0) And (MeshMotion.SKeys[0].Time = 0) Then
Begin
Matrix2 := CreateScaleMatrix(TAffineVector(MeshMotion.Scale[0]));
Matrix := MatrixMultiply(Matrix, Matrix2);
End;

// open the door
Matrix2 := CreateRotationMatrix(MakeAffineVector([RotX, RotY, RotZ]), 1);
Matrix := MatrixMultiply(Matrix, Matrix2);

// move door to doorframe
If (MeshMotion.NRKeys > 0) And (MeshMotion.RKeys[0].Time = 0) Then
Begin
Matrix2 := CreateRotationMatrix(MakeAffineVector([MeshMotion.Rot[0].X, MeshMotion.Rot[0].Y, MeshMotion.Rot[0].Z]), MeshMotion.Rot[0].Angle);
Matrix := MatrixMultiply(Matrix, Matrix2);
End;

// translation
If (MeshMotion.NPKeys > 0) And (MeshMotion.PKeys[0].Time = 0) Then
Begin
Matrix[3, 0] := Matrix[3, 0] + MeshMotion.Pos[0].X;
Matrix[3, 1] := Matrix[3, 1] + MeshMotion.Pos[0].Y;
Matrix[3, 2] := Matrix[3, 2] + MeshMotion.Pos[0].Z;
End;

glPushMatrix;
glMultMatrixf(@Matrix);
0

Author Commented:
err... I think I understand that.  I'll let you know how I get on.

Cheers
John.
0

Author Commented:
Excellant, works very nicely indeed.

Thanks
Woody.
0

Commented:
Fine, I'm glad that I could help...

Ciao, Mike
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.