How does rotation work?

A place to discuss everything related to Newton Dynamics.

Moderators: Sascha Willems, walaber

How does rotation work?

Postby Henry00 » Sat Aug 06, 2011 4:41 pm

Hi everyone, I was playing around with a fully working set of a floor and two barrels, and came to notice I require some rotation...

Matrix contains 9 changing values?! I can only give a yaw pitch roll of 0-360, and the quaternions are also not working very well, could someone tell me how to get a simple basic yaw pitch and roll?

Thanks!

EDIT DUE TO SOLUTION

Ether you implent all the matrix, or if you are like me a bit less on the powerfull math skills, use:

Dim Angles.f(2) // create 3 floats to store the angles in
NewtonGetEulerAngle( @Pmatrix(), @Angles() ) // ask newton for the angles of the Euler
GameObject_Rotation( *GameObject, Degree(Angles(0)), Degree(Angles(1)), Degree(Angles(2)) ) // convert yaw pitch roll to Degrees, and rotate your actual mesh file until you get it right ingame.

Good luck!
Last edited by Henry00 on Mon Aug 08, 2011 6:04 pm, edited 1 time in total.
00Laboratories
Solutions for Developers
http://00laboratories.com/
Henry00
 
Posts: 37
Joined: Mon Aug 01, 2011 7:29 pm
Location: Germany

Re: How does rotation work?

Postby JoeJ » Sun Aug 07, 2011 3:57 am

Yaw pitch and roll are the same as euler angles, which represent orientation by a combination of 3 rotations about the x, y, z axis.
The problem is that the order is important, you can get the same orientation with order xyz or zyx or xzy... but the angles would be different.
Something like xzx is also possible, but i'm not shure if my code can handle this and you'll not need it.

In my code the order is constant in both functions, defined by "int order", given as hexadezimal number.
That's a compressed way to store 3 indices, each 4 bits in a single 32 bit number.
I've commented and i hope you can read it, translate it to basic either using an array with 3 values or keep the bit logic style.
By trial and error you can find the order you want, 012, 210, 021...

The code operates on 4x4 matrices (16 values, same as newton, and same as illustrated in last topic).
It would work on 3x3 matrices too (9 values).
A 3x3 matrix can store orientation, but no position and is included in top left of a 4x4 matrix.
As noted the mtarices contain the 3 basis vectors (x,y,z Axis), mostly displayed as red, green and blue vectors form the center in 3D Modellers & Editors.
Thats the best way to imagine orientation.

Rotation is similar to orientation, as translation is similar to position (vector to point).
You can represent rotation like orientation an vice versa.
To avoid the order problem, the best way to imagine rotation is:
A direction vector and a single angle that rotates around this vector (called axis and angle rotation, which can represent any rotation).
That's where quaternions come handy, as they encode this axis and angle somehow in 4 values.
With quats it's easy for ex. to interpolate nicely between 2 or more orientations, which is horror using matrices.
You can convert between matrix and quat form.

What you need is a math library that contains 3d vectors, 3x3 Matrices, 4x4 Matrices, Quaternions.
I guess DirectX contains that all, Newton contains one,...
Most of them include the code below too, but mostly the order is hardcoded, so it might be useful.






Code: Select all

void CalcOrientationMatrix (matrix4f &m, v3f rotation)
{
      int order = 0x012;//xyz // 0x means hexadezimal

      int a0 = (order>>8)&3; // extract 1st (0x0**) = 0
      int a1 = (order>>4)&3; // extract 2nd (0x*1*) = 1
      int a2 = (order>>0)&3; // extract 3rd (0x**2) = 2

      matrix4f r[3];
      r[0].XRot (DEG_TO_RAD(rotation.x)); // construct rotation matrix around x axis, deg to rad is simply degrees to radians
      r[1].YRot (DEG_TO_RAD(rotation.y));
      r[2].ZRot (DEG_TO_RAD(rotation.z));

      m = r[a0];
      m *= r[a1];
      m *= r[a2];
}
v3f ToEulerAngles (matrix4f &m)
{
      int order = 0x012;//xyz
      int a0 = (order>>8)&3;
      int a1 = (order>>4)&3;
      int a2 = (order>>0)&3;

      v3f euler;
      // Assuming the angles are in radians.
      if (m.m[a0][a2] > 0.998)
      { // singularity at north pole
         euler[a0] = -atan2(m.m[a2][a1], m.m[a1][a1]);
         euler[a1] = -PI/2;
         euler[a2] = 0;
         return euler;
      }
      if (m.m[a0][a2] < -0.998)
      { // singularity at south pole
         euler[a0] = -atan2(m.m[a2][a1], m.m[a1][a1]);
         euler[a1] = PI/2;
         euler[a2] = 0;
         return euler;
      }
      euler[a0] =   -atan2(-m.m[a1][a2], m.m[a2][a2]);
      euler[a1] =   -asin ( m.m[a0][a2]);
      euler[a2] =   -atan2(-m.m[a0][a1], m.m[a0][a0]);
      return euler;
}
User avatar
JoeJ
 
Posts: 1489
Joined: Tue Dec 21, 2010 6:18 pm

Re: How does rotation work?

Postby Henry00 » Sun Aug 07, 2011 12:21 pm

Definitly thanks for this awnser it's really full with information on how to solve this and more, but I don't have any special way to calculate matrices like you do in your code, I always have a little array of 16 floats ( as you know from the other topic ) and I am a little confused on how to calculate matrices like you do in your code, but I also read:

What you need is a math library that contains 3d vectors, 3x3 Matrices, 4x4 Matrices, Quaternions.
I guess DirectX contains that all, Newton contains one,...


Newton contains one? If so that would be great, on wiki and many other sites I only find weird math algebra on how to calculate matrices, could you by any chance give me an idea how to calculate this without matrices.. seeing it as 16 floats? Sorry for the trouble :(

Code: Select all
m *= r[a1];

Well m seems to be a 4x4 matrix so I would have no idea how to calculate this, I just have 16 floats.. And no as you probably noticed my math skills aren't the best hehe
00Laboratories
Solutions for Developers
http://00laboratories.com/
Henry00
 
Posts: 37
Joined: Mon Aug 01, 2011 7:29 pm
Location: Germany

Re: How does rotation work?

Postby JoeJ » Sun Aug 07, 2011 1:17 pm

Here is the entire matrix class.
The 16 values are stored in the 2 dimensional array m[4][4], using a one dimensional array m1d[16] would work too,
but this way it's easier to understand. m[1][3] would be the same as m1d[1*4 + 3].

The Newton lib is in a folder "dMath".
It stores the values in 4 4D vectors, but in principial it's the same.
I'm unsure you can use C structs and classes directly, most probably you need to translate the functions to basic on demand,
which would be some learning experience.

The matrix multiplication you quotet is compact code as you see.
Treat it as an application of dot products, it's the key to understend all of that in one go without algebra background.
Figure out what the dot product does to understand how to rotate a vector from one orientation to another.
The rest is trivial, it's explained in detail in Gibbons threads.

Code: Select all
class matrix4f
{
public:

   float m[4][4];

   void ToM3 (float *t) // copy rotation to 3x3 matrix
   {
      for (int j=0;j<3;j++)
         for (int i=0;i<3;i++)
            t[i*3+j] = m[i][j];
   }
   
   void XRot ( float a )
   {
      float c = (float) cos (a);
      float s = (float) sin (a);

      m[0][0] = 1;   m[0][1] = 0;    m[0][2] = 0;    m[0][3] = 0;
      m[1][0] = 0;   m[1][1] = c;    m[1][2] = s;    m[1][3] = 0;
      m[2][0] = 0;   m[2][1] = -s;   m[2][2] = c;    m[2][3] = 0;
      m[3][0] = 0;   m[3][1] = 0;    m[3][2] = 0;    m[3][3] = 1;
   }

   void YRot( float a )
   {
      float c = (float) cos (a);
      float s = (float) sin (a);

      m[0][0] = c;   m[0][1] = 0;    m[0][2] = -s;   m[0][3] = 0;
      m[1][0] = 0;   m[1][1] = 1;    m[1][2] = 0;    m[1][3] = 0;
      m[2][0] = s;   m[2][1] = 0;    m[2][2] = c;    m[2][3] = 0;
      m[3][0] = 0;   m[3][1] = 0;    m[3][2] = 0;    m[3][3] = 1;
   }

   void ZRot( float a )
   {
      float c = (float) cos (a);
      float s = (float) sin (a);

      m[0][0] = c;   m[0][1] = s;    m[0][2] = 0;    m[0][3] = 0;
      m[1][0] = -s;   m[1][1] = c;    m[1][2] = 0;    m[1][3] = 0;
      m[2][0] = 0;   m[2][1] = 0;    m[2][2] = 1;    m[2][3] = 0;
      m[3][0] = 0;   m[3][1] = 0;    m[3][2] = 0;    m[3][3] = 1;
   }

   void Idnt( void ) // identity - no rotation or translation
   {
      m[0][0] = 1;   m[0][1] = 0;    m[0][2] = 0;    m[0][3] = 0;
      m[1][0] = 0;   m[1][1] = 1;    m[1][2] = 0;    m[1][3] = 0;
      m[2][0] = 0;   m[2][1] = 0;    m[2][2] = 1;    m[2][3] = 0;
      m[3][0] = 0;   m[3][1] = 0;    m[3][2] = 0;    m[3][3] = 1;
   }

   void Tlat( vector3f *c ) // translate
   {
      m[0][0] = 1;   m[0][1] = 0;    m[0][2] = 0;    m[0][3] = 0;
      m[1][0] = 0;   m[1][1] = 1;    m[1][2] = 0;    m[1][3] = 0;
      m[2][0] = 0;   m[2][1] = 0;    m[2][2] = 1;    m[2][3] = 0;
      m[3][0] = c->x;   m[3][1] = c->y;   m[3][2] = c->z;   m[3][3] = 1;
   }

   void Scale( vector3f *c )
   {
      m[0][0] = c->x;   m[0][1] = 0;    m[0][2] = 0;    m[0][3] = 0;
      m[1][0] = 0;   m[1][1] = c->y;   m[1][2] = 0;    m[1][3] = 0;
      m[2][0] = 0;   m[2][1] = 0;    m[2][2] = c->z;   m[2][3] = 0;
      m[3][0] = 0;   m[3][1] = 0;    m[3][2] = 0;    m[3][3] = 1;
   }

   void ScaleRotation ( vector3f *c )
   {
      ((v3f&) m[0][0]) *= c->x;
      ((v3f&) m[1][0]) *= c->y;
      ((v3f&) m[2][0]) *= c->z;
   }

   void Sheer( float xy, float yz, float zx, float xz, float yx, float zy )
   {
      m[0][0] = 1;   m[0][1] = xy;   m[0][2] = xz;   m[0][3] = 0;
      m[1][0] = yx;   m[1][1] = 1;   m[1][2] = yz;   m[1][3] = 0;
      m[2][0] = zx;   m[2][1] = zy;   m[2][2] = 1;   m[2][3] = 0;
      m[3][0] = 0;   m[3][1] = 0;   m[3][2] = 0;   m[3][3] = 1;
   }
   
   void operator *= ( matrix4f& b ) // multiplication
   {   
      matrix4f t;
      int i,j;

      for (j=0;j<4;j++)
         for (i=0;i<4;i++)
            t.m[i][j] = m[i][0] * b.m[0][j] + m[i][1] * b.m[1][j] + m[i][2] * b.m[2][j] + m[i][3] * b.m[3][j];

      for (j=0;j<4;j++)
         for (i=0;i<4;i++)
            m[i][j] = t.m[i][j];
   }

   void SetMul (matrix4f& a, matrix4f& b) // more efficient mult: this = a * b
   {   
      int i,j;

      for (j=0;j<4;j++)
         for (i=0;i<4;i++)
            m[i][j] = a.m[i][0] * b.m[0][j] + a.m[i][1] * b.m[1][j] + a.m[i][2] * b.m[2][j] + a.m[i][3] * b.m[3][j];
   }

   void SetXAxis ( vector3f *c ) { (v3f&) (m[0][0]) = *c; }
   vector3f* GetXAxis () { return (v3f*) &m[0][0]; }
   void SetYAxis ( vector3f *c ) { (v3f&) (m[1][0]) = *c; }
   vector3f* GetYAxis () { return (v3f*) &m[1][0]; }
   void SetZAxis ( vector3f *c ) { (v3f&) (m[2][0]) = *c; }
   vector3f* GetZAxis () { return (v3f*) &m[2][0]; }
   
   void SetTranslation ( vector3f *c )
   {   
      (v3f&) (m[3][0]) = *c;
   }
   vector3f* GetTranslation ()
   {   
      return (v3f*) &m[3][0];
   }
   
   void ClearTranslation ()
   {   
      m[3][0] = m[3][1] = m[3][2] = 0;
   }

   void TrnsVec ( vector3f &d, vector3f &s ) // transform a point by this
   {
      d.x = ( s.x * m[0][0] ) + ( s.y * m[1][0] ) + ( s.z * m[2][0]) + m[3][0];
      d.y = ( s.x * m[0][1] ) + ( s.y * m[1][1] ) + ( s.z * m[2][1]) + m[3][1];
      d.z = ( s.x * m[0][2] ) + ( s.y * m[1][2] ) + ( s.z * m[2][2]) + m[3][2];   
   }

   void TrnsDir ( vector3f &d, vector3f &s ) // rotate a vector by this (ignoring position)
   {
      d.x = ( s.x * m[0][0] ) + ( s.y * m[1][0] ) + ( s.z * m[2][0]);
      d.y = ( s.x * m[0][1] ) + ( s.y * m[1][1] ) + ( s.z * m[2][1]);
      d.z = ( s.x * m[0][2] ) + ( s.y * m[1][2] ) + ( s.z * m[2][2]);   
   }

   void TrnsVec ( vector3f &d ) // the same as above, source = destination vector
   {
      float x,y,z;
      x = d.x;
      y = d.y;
      z = d.z;
      d.x = ( x * m[0][0] ) + ( y * m[1][0] ) + ( z * m[2][0]) + m[3][0];
      d.y = ( x * m[0][1] ) + ( y * m[1][1] ) + ( z * m[2][1]) + m[3][1];
      d.z = ( x * m[0][2] ) + ( y * m[1][2] ) + ( z * m[2][2]) + m[3][2];   
   }

   void TrnsDir ( vector3f &d )
   {
      float x,y,z;
      x = d.x;
      y = d.y;
      z = d.z;
      d.x = ( x * m[0][0] ) + ( y * m[1][0] ) + ( z * m[2][0]);
      d.y = ( x * m[0][1] ) + ( y * m[1][1] ) + ( z * m[2][1]);
      d.z = ( x * m[0][2] ) + ( y * m[1][2] ) + ( z * m[2][2]);   
   }

   void TinvVec ( vector3f &d, vector3f &s ) // inverse transform = untransform
   {
      float x,y,z;
      x = s.x - m[3][0];
      y = s.y - m[3][1];
      z = s.z - m[3][2];
      d.x = ( x * m[0][0] ) + ( y * m[0][1] ) + ( z * m[0][2] );
      d.y = ( x * m[1][0] ) + ( y * m[1][1] ) + ( z * m[1][2] );
      d.z = ( x * m[2][0] ) + ( y * m[2][1] ) + ( z * m[2][2] );
   }

   void TinvDir ( vector3f &d, vector3f &s ) // unrotate
   {
      d.x = ( s.x * m[0][0] ) + ( s.y * m[0][1] ) + ( s.z * m[0][2] );
      d.y = ( s.x * m[1][0] ) + ( s.y * m[1][1] ) + ( s.z * m[1][2] );
      d.z = ( s.x * m[2][0] ) + ( s.y * m[2][1] ) + ( s.z * m[2][2] );   
   }

   void TinvVec ( vector3f &d )
   {
      float x,y,z;
      x = d.x - m[3][0];
      y = d.y - m[3][1];
      z = d.z - m[3][2];
      d.x = ( x * m[0][0] ) + ( y * m[0][1] ) + ( z * m[0][2] );
      d.y = ( x * m[1][0] ) + ( y * m[1][1] ) + ( z * m[1][2] );
      d.z = ( x * m[2][0] ) + ( y * m[2][1] ) + ( z * m[2][2] );   
   }

   void TinvDir ( vector3f &d )
   {
      float x,y,z;
      x = d.x;
      y = d.y;
      z = d.z;
      d.x = ( x * m[0][0] ) + ( y * m[0][1] ) + ( z * m[0][2] );
      d.y = ( x * m[1][0] ) + ( y * m[1][1] ) + ( z * m[1][2] );
      d.z = ( x * m[2][0] ) + ( y * m[2][1] ) + ( z * m[2][2] );   
   }

   matrix4f()
   {
      //Idnt();
   }


   void FlipOrder ( void ) // this class uses OpenGL order, this swaps rows and columns to be DirectX compatible, but that's anoter story
   {
      matrix4f temp;

      for (int j=0;j<4;j++)
         for (int i=0;i<4;i++)
            temp.m[i][j] = m[j][i];

      *this = temp;
   }

   
   
};



and to be complete, the vector class...

Code: Select all
class vector3f
{

public:
   
   float x,y,z;

public:

   vector3f()
   : x(0), y(0), z(0)
   {}

   vector3f( const float& a, const float& b, const float& c )
   : x(a), y(b), z(c)
   {}

   float& operator [] ( const int i )
   {
      return *((&x) + i);
   }

   const bool operator == ( const vector3f& v ) const
   {
      return (v.x==x && v.y==y && v.z==z);
   }

   const vector3f operator - () const
   {
      return vector3f( -x, -y, -z );
   }

   const vector3f& operator = ( const vector3f& v )
   {
      x = v.x; y = v.y; z = v.z;
      return *this;
   }

   const vector3f& operator += ( const vector3f& v )
   {
      x+=v.x; y+=v.y; z+=v.z;
      return *this;
   }

   const vector3f& operator -= ( const vector3f& v )
   {
      x-=v.x; y-=v.y; z-=v.z;
      return *this;
   }

   const vector3f& operator *= ( const float& s )
   {
      x*=s; y*=s; z*=s;
      return *this;
   }

   const vector3f& operator /= ( const float& s )
   {
      const float r = 1 / s;
      x *= r; y *= r; z *= r;
      return *this;
   }

   const vector3f operator + ( const vector3f& v ) const
   {
      return vector3f(x + v.x, y + v.y, z + v.z);
   }

   const vector3f operator - ( const vector3f& v ) const
   {
      return vector3f(x - v.x, y - v.y, z - v.z);
   }

   const vector3f operator * ( const float& s ) const
   {
      return vector3f( x*s, y*s, z*s );
   }

   friend inline const vector3f operator * ( const float& s, const vector3f& v )
   {
      return v * s;
   }

   const vector3f operator / (float s) const
   {
      s = 1/s;
      return vector3f( s*x, s*y, s*z );
   }

   const vector3f Cross( const vector3f& v ) const
   {
      return vector3f( y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x );
   }

   const float Dot( const vector3f& v ) const
   {
      return x*v.x + y*v.y + z*v.z;
   }

   const float Length() const
   {
      return (float)sqrt( (double)this->Dot(*this) );
   }

   const float SqL() const
   {
      return x*x + y*y + z*z;
   }

   const vector3f Unit() const
   {
      return (*this) / Length();
   }

   void Normalize()
   {
      (*this) /= Length();
   }

   const vector3f SafeUnit() const
   {
      float sql = SqL();
      if (sql > 0.00001) return (*this) / (float) sqrt ((double)sql);
      else return vector3f(0,0,1);
   }

   void SafeNormalize()
   {
      float sql = SqL();
      if (sql > 0.00001) (*this) /= (float) sqrt ((double)sql);
      else (*this) = vector3f(0,0,1);
   }

   


};

typedef vector3f v3f;


EDIT: added comments
User avatar
JoeJ
 
Posts: 1489
Joined: Tue Dec 21, 2010 6:18 pm

Re: How does rotation work?

Postby Henry00 » Sun Aug 07, 2011 4:21 pm

Thanks! I am on the edge of getting this done, but now something else is bothering me haha, will this ever stop who knows.. lol

NewtonCollisionForEachPolygonDo

I mean it's great the wiki has the functions, but they forget to say the callback's parameters on every single topic, how lame
00Laboratories
Solutions for Developers
http://00laboratories.com/
Henry00
 
Posts: 37
Joined: Mon Aug 01, 2011 7:29 pm
Location: Germany

Re: How does rotation work?

Postby nickersonm » Sun Aug 07, 2011 7:35 pm

It says the callback is of type NewtonCollisionIterator. Which is defined as:
Code: Select all
typedef void (_cdecl *NewtonCollisionIterator) (const NewtonBody* body, int vertexCount, const float* FaceArray, int faceId);
nickersonm
 
Posts: 3
Joined: Thu Aug 28, 2008 1:37 pm

Re: How does rotation work?

Postby Henry00 » Mon Aug 08, 2011 3:35 am

nickersonm wrote:It says the callback is of type NewtonCollisionIterator. Which is defined as:
Code: Select all
typedef void (_cdecl *NewtonCollisionIterator) (const NewtonBody* body, int vertexCount, const float* FaceArray, int faceId);


Which is deprecated ever since Newton2, I don't have the C variant anymore but it's like this, took me a long time to find:

Newton_DrawCollisionProcedure(*userData, vertexCount.i, *faceVertec, id.i)
00Laboratories
Solutions for Developers
http://00laboratories.com/
Henry00
 
Posts: 37
Joined: Mon Aug 01, 2011 7:29 pm
Location: Germany


Return to General Discussion

Who is online

Users browsing this forum: No registered users and 1 guest