Solved

Combining Rotation Matricies

Posted on 2000-04-07
16
387 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
Gigs: Get Your Project Delivered by an Expert

Select from freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely and get projects done right.

 
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
 

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

Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
This Micro Tutorial will give you a basic overview how to record your screen with Microsoft Expression Encoder. This program is still free and open for the public to download. This will be demonstrated using Microsoft Expression Encoder 4.
Windows 10 is mostly good. However the one thing that annoys me is how many clicks you have to do to dial a VPN connection. You have to go to settings from the start menu, (2 clicks), Network and Internet (1 click), Click VPN (another click) then fi…

813 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

10 Experts available now in Live!

Get 1:1 Help Now