• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 414
  • Last Modified:

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.
0
WoodyJ3
Asked:
WoodyJ3
  • 8
  • 7
1 Solution
 
LischkeCommented:
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
 
WoodyJ3Author 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
 
LischkeCommented:
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
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
jeurkCommented:
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
 
LischkeCommented:
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
 
LischkeCommented:
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
 
WoodyJ3Author 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
 
WoodyJ3Author 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
 
WoodyJ3Author 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.
//------------------------------------------------------------------------------
Procedure ManipulateObject(Var GLReader : TGLReader; MeshMotion : TKFMesh3DS; ListIndex : Integer;
   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
   glDeleteLists(StrToInt(GLReader.GlLists[ListIndex]), 1);

   NewList := glGenLists(1);

   glNewList(NewList, GL_COMPILE);

   GLReader.GlLists[ListIndex] := IntToStr(NewList);

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

   Matrix := InvertMeshMatrix(GLReader.Reader, MeshMotion.Name);

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

   ParentMotionIndex := FindMotionIndex(GLReader, MeshMotion.Parent);

   While ParentMotionIndex > -1 Do
   Begin
      ParentMeshMotion := GLReader.Reader.Keyframer.MeshMotion[ParentMotionIndex]^;

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

      ParentMotionIndex := FindMotionIndex(GLReader, ParentMeshMotion.Parent);
   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);


   MeshIndex := FindMeshIndex(GLReader, MeshMotion.Name);

   Mesh := GLReader.MeshLists[MeshIndex];

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

   glPopMatrix;

   glEndList;
   CheckOpenGLError;

   If RedrawScene Then
      InvalidateScene;
End;
0
 
LischkeCommented:
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
 
LischkeCommented:
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
 
WoodyJ3Author 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.


Matrix := InvertMeshMatrix(GLReader.Reader, MeshMotion.Name);

   // 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
 
LischkeCommented:
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
 
WoodyJ3Author Commented:
err... I think I understand that.  I'll let you know how I get on.

Cheers
John.
0
 
WoodyJ3Author Commented:
Excellant, works very nicely indeed.

Thanks
Woody.
0
 
LischkeCommented:
Fine, I'm glad that I could help...

Ciao, Mike
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 8
  • 7
Tackle projects and never again get stuck behind a technical roadblock.
Join Now