Solved

Combining Rotation Matricies

Posted on 2000-04-07
16
381 Views
Last Modified: 2010-04-04
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
Comment
Question by:WoodyJ3
  • 8
  • 7
16 Comments
 
LVL 10

Expert Comment

by:Lischke
ID: 2692639
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 Comment

by:WoodyJ3
ID: 2692689
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
 
LVL 10

Expert Comment

by:Lischke
ID: 2692718
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
 
LVL 4

Expert Comment

by:jeurk
ID: 2692766
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
 
LVL 10

Expert Comment

by:Lischke
ID: 2692929
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
 
LVL 10

Expert Comment

by:Lischke
ID: 2692940
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 Comment

by:WoodyJ3
ID: 2692858
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 Comment

by:WoodyJ3
ID: 2693039
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
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 

Author Comment

by:WoodyJ3
ID: 2693064
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
 
LVL 10

Expert Comment

by:Lischke
ID: 2693135
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
 
LVL 10

Expert Comment

by:Lischke
ID: 2693138
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 Comment

by:WoodyJ3
ID: 2693244
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
 
LVL 10

Accepted Solution

by:
Lischke earned 160 total points
ID: 2693296
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
 

Author Comment

by:WoodyJ3
ID: 2693394
err... I think I understand that.  I'll let you know how I get on.

Cheers
John.
0
 

Author Comment

by:WoodyJ3
ID: 2703694
Excellant, works very nicely indeed.

Thanks
Woody.
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2703748
Fine, I'm glad that I could help...

Ciao, Mike
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Suggested Solutions

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now