Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Rotation Matrix


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
3 replies to this topic

#1 PRO_Muffy   Members   -  Reputation: 122

Like
0Likes
Like

Posted 06 April 2007 - 12:16 AM

Hi all, this is my first post on these forums. I've been searching about a bit to get a feel for the forum and so wasnt sure whether it would be welcomed if I landed a big chunk of code in my first post. I noticed another closed thread on something similar here on the same topic as this on this forum: http://www.gamedev.net/community/forums/topic.asp?topic_id=432027

For the last week or so, I've been trying to write my own rotation matrix. I do mean day in, day out staring at the same 30 or so lines of code. At first I tried to use an algorithm that would rotate a point around an arbitrary axis by combining three rotation matrices, one for each of the X, Y and Z axes into one matrix calculation but I couldn't get this to work. I then had a look at some of the pixel shader examples in RenderMonkey 1.62 and tried to port across an algorithm using Euler angles from GLSL to C++, and this had pretty much the same result. I then had another look at the problem and broke it down into the elements so that I was creating the X, Y and Z rotation matrices seperately.

I've emailed my lecturers with code and so far I've had two responses, one saying "can't see anything obvious" and to the second suggesting a few alterations to the code. I've performed these alterations but I'm getting the same effect. For now I'm using a simple sphere object extended from a base graphic object class where the vertices are stored in a vertex array (*)(3). Using each matrix individually yields different results. Using the Y axis rotation matrix, the sphere rotates around the Y axis (it spins) and shrinks in size gradually over time. Using the X axis rotation matrix, the sphere rotates around the X axis but the sphere coordinates are flattened on the Z axis. Again over time it scales. Using the Z axis rotation matrix, a similar thing happens but rotation takes place around the Z axis and flattening occurs to the X coordinate.

I wasnt sure if it was a good idea to post a lot of C++ on my first go. It's not so much about the code as the underlying algorithm that's causing problems. I feel I'm so close to the code I can't see the problem and I have tried working out the algorithm seperately. Does anyone have any suggestions?

Quote:

/***********************************************************************
Update the player - This is performed before GraphicObject::Rotate() so that the value to rotate by is set
***********************************************************************/
void Player::Update(void)
{
// Update dt value
dt = (float)timer.GetDT();

float rotationInDegrees = 30.0f;
float rotationInRadians = rotationInDegrees*dt*(PI/180.0f);

rotation.xyzw[0] = rotationInRadians;
rotation.xyzw[1] = rotationInRadians;
rotation.xyzw[2] = rotationInRadians;

SetRotation(rotation);
}


/*******************************************************************************
Rotate this graphicobject's vertices
*******************************************************************************/
void GraphicObject::Rotate(const float rotateX, const float rotateY, const float rotateZ)
{

// Rotation about an arbitrary axis
Matrix33f rotationMatrixX;
Matrix33f rotationMatrixY;
Matrix33f rotationMatrixAll;

rotationMatrixX.MakeRotationMatrixX(rotation.xyzw[0]);
rotationMatrixY.MakeRotationMatrixY(rotation.xyzw[1]);
rotationMatrixAll.MakeRotationMatrixZ(rotation.xyzw[2]);

rotationMatrixAll.MultiplyThis(rotationMatrixX);
rotationMatrixAll.MultiplyThis(rotationMatrixY);

// Update vertices
Vector3f temp;
for (int i = 0; i < numberOfVertices; i++)
{
temp.Set3f(vertexArray[i][0], vertexArray[i][1], vertexArray[i][2]);
temp.MultiplyThis33f(rotationMatrixAll);
vertexArray[i][0] = temp.xyz[0];
vertexArray[i][1] = temp.xyz[1];
vertexArray[i][2] = temp.xyz[2];
}

// TODO: update normals!
}


/*******************************************************************************
Creates a rotation matrix which vector3fs can be multiplied to rotate around the
X axis
*******************************************************************************/
void Matrix33f::MakeRotationMatrixX(float angle)
{
float fCos = cosf(angle);
float fSin = sinf(angle);
m[0][0] = 1.0f; m[1][0] = 0.0f; m[2][0] = 0.0f;
m[0][1] = 0.0f; m[1][1] = fCos; m[2][1] = fSin;
m[0][2] = 0.0f; m[1][2] = -fSin; m[2][2] = fCos;
}


/*******************************************************************************
Creates a rotation matrix which vector3fs can be multiplied to rotate around the
Y axis
*******************************************************************************/
void Matrix33f::MakeRotationMatrixY(float angle)
{
float fCos = cosf(angle);
float fSin = sinf(angle);
m[0][0] = fCos; m[1][0] = 0.0f; m[2][0] = -fSin;
m[0][1] = 0.0f; m[1][1] = 1.0f; m[2][1] = 0.0f;
m[0][2] = fSin; m[1][2] = 0.0f; m[2][2] = fCos;
}


/*******************************************************************************
Creates a rotation matrix which vector3fs can be multiplied to rotate around the
Z axis
*******************************************************************************/
void Matrix33f::MakeRotationMatrixZ(float angle)
{
float fCos = cosf(angle);
float fSin = sinf(angle);
m[0][0] = fCos; m[1][0] = fSin; m[2][0] = 0.0f;
m[0][1] = -fSin; m[1][1] = fCos; m[2][1] = 0.0f;
m[0][2] = 0.0f; m[1][2] = 0.0f; m[2][2] = 1.0f;
}



/*******************************************************************************
Multiply this Matrix33f by another Matrix33f
*******************************************************************************/
void Matrix33f::MultiplyThis(Matrix33f& a)
{
// Calculate the dot products
m[0][0] = m[0][0]*a.m[0][0] + m[0][1]*a.m[1][0] + m[0][2]*a.m[2][0];
m[1][0] = m[0][0]*a.m[0][1] + m[0][1]*a.m[1][1] + m[0][2]*a.m[2][1];
m[2][0] = m[0][0]*a.m[0][2] + m[0][1]*a.m[1][2] + m[0][2]*a.m[2][2];

m[0][1] = m[1][0]*a.m[0][0] + m[1][1]*a.m[1][0] + m[1][2]*a.m[2][0];
m[1][1] = m[1][0]*a.m[0][1] + m[1][1]*a.m[1][1] + m[1][2]*a.m[2][1];
m[2][1] = m[1][0]*a.m[0][2] + m[1][1]*a.m[1][2] + m[1][2]*a.m[2][2];

m[0][2] = m[2][0]*a.m[0][0] + m[2][1]*a.m[1][0] + m[2][2]*a.m[2][0];
m[1][2] = m[2][0]*a.m[0][1] + m[2][1]*a.m[1][1] + m[2][2]*a.m[2][1];
m[2][2] = m[2][0]*a.m[0][2] + m[2][1]*a.m[1][2] + m[2][2]*a.m[2][2];
}


/*******************************************************************************
Multiply this vector by a matrix33f
*******************************************************************************/
void Vector3f::MultiplyThis33f(Matrix33f& mat)
{
xyz[0] = mat.m[0][0]*xyz[0] + mat.m[0][1]*xyz[1] + mat.m[0][2]*xyz[2];
xyz[1] = mat.m[1][0]*xyz[0] + mat.m[1][1]*xyz[1] + mat.m[1][2]*xyz[2];
xyz[2] = mat.m[2][0]*xyz[0] + mat.m[2][1]*xyz[1] + mat.m[2][2]*xyz[2];
}


Sponsor:

#2 scgames   Members   -  Reputation: 2049

Like
0Likes
Like

Posted 06 April 2007 - 05:51 AM

Only have time for a quick look at the moment, but here:
m[0][0] = m[0][0]*a.m[0][0] + m[0][1]*a.m[1][0] + m[0][2]*a.m[2][0];
m[1][0] = m[0][0]*a.m[0][1] + m[0][1]*a.m[1][1] + m[0][2]*a.m[2][1];
m[2][0] = m[0][0]*a.m[0][2] + m[0][1]*a.m[1][2] + m[0][2]*a.m[2][2];

m[0][1] = m[1][0]*a.m[0][0] + m[1][1]*a.m[1][0] + m[1][2]*a.m[2][0];
m[1][1] = m[1][0]*a.m[0][1] + m[1][1]*a.m[1][1] + m[1][2]*a.m[2][1];
m[2][1] = m[1][0]*a.m[0][2] + m[1][1]*a.m[1][2] + m[1][2]*a.m[2][2];

m[0][2] = m[2][0]*a.m[0][0] + m[2][1]*a.m[1][0] + m[2][2]*a.m[2][0];
m[1][2] = m[2][0]*a.m[0][1] + m[2][1]*a.m[1][1] + m[2][2]*a.m[2][1];
m[2][2] = m[2][0]*a.m[0][2] + m[2][1]*a.m[1][2] + m[2][2]*a.m[2][2];
It looks like you're overwriting the elements of m as you go, which means the results of the operation will be more or less meaningless (this may be why your objects are being scaled as they rotate).

To correct this, you'll need to store the result of the multiplication in a temporary matrix, and then assign this matrix to m (or just store individual elements as needed).

As for constructing a matrix to rotate one vector about another, it's not necessary to compose such a matrix from individual rotations. A Google search for 'axis angle matrix' should turn up plenty of info on the correct (or at least most straightforward) way to do this.

Here's some code you can use as a reference:


/** Build a rotation matrix from an axis-angle pair */
template < typename E, class A, class B, class L, class VecT > void
matrix_rotation_axis_angle(matrix<E,A,B,L>& m, const VecT& axis, E angle)
{
typedef matrix<E,A,B,L> matrix_type;
typedef typename matrix_type::value_type value_type;

/* Checking */
detail::CheckMatLinear3D(m);
detail::CheckVec3(axis);

identity_transform(m);

value_type s = std::sin(angle);
value_type c = std::cos(angle);
value_type omc = value_type(1) - c;

value_type xomc = axis[0] * omc;
value_type yomc = axis[1] * omc;
value_type zomc = axis[2] * omc;

value_type xxomc = axis[0] * xomc;
value_type yyomc = axis[1] * yomc;
value_type zzomc = axis[2] * zomc;
value_type xyomc = axis[0] * yomc;
value_type yzomc = axis[1] * zomc;
value_type zxomc = axis[2] * xomc;

value_type xs = axis[0] * s;
value_type ys = axis[1] * s;
value_type zs = axis[2] * s;

m.set_basis_element(0,0, xxomc + c );
m.set_basis_element(0,1, xyomc + zs);
m.set_basis_element(0,2, zxomc - ys);
m.set_basis_element(1,0, xyomc - zs);
m.set_basis_element(1,1, yyomc + c );
m.set_basis_element(1,2, yzomc + xs);
m.set_basis_element(2,0, zxomc + ys);
m.set_basis_element(2,1, yzomc - xs);
m.set_basis_element(2,2, zzomc + c );
}



#3 David Neubelt   Members   -  Reputation: 794

Like
0Likes
Like

Posted 06 April 2007 - 09:11 AM

Quote:
Original post by jyk
....
It looks like you're overwriting the elements of m as you go, which means the results of the operation will be more or less meaningless (this may be why your objects are being scaled as they rotate).


I remember getting bit by that same bug on my first time implementing matrix operations in code. Don't feel bad :)

Though, as far as debugging math problems you should take a different approach to solving this problem. I believe if you did you would have figured this out on your own very quickly.

1) Determine the problem
- You knew the problem already so this was easy. The problem was that after a rotation the sphere scales

2) Find a simple test case
- Well, a simple test case would be to multiply a point, say at (1,0,0) by a rotation of 90 degree about the z-axis. We know in our head the result of this operation to be <0,1,0>.

3) Show each step on paper
- This would be to calculate all the steps of the matrix multiply one line at a time.

4) Debug the simple test case
- You already have the correct answer on paper so stepping through the problem in the debugger one line at a time would have shown the case where the values were being stomped.

Good luck!

-= Dave

#4 PRO_Muffy   Members   -  Reputation: 122

Like
0Likes
Like

Posted 07 April 2007 - 10:50 AM

Jyk, you're an absolute star! I knew it was somewhere in my algorithm. I had actually worked it out for a 30 degree rotation on paper, but couldnt work out what was causing it to go wrong. I didnt check the individual values during the multiplication which with hindsight was a bit daft. I think I'd been staring at it for too long. I wrote the "MultiplyThis" functions into my vector and matrix classes more recently and completely forgot the issue of temporary variables. They werent actually necessary either. I changed one line in my code and it now has the desired effect.

In the Rotate() function...

Quote:

temp.MultiplyThis33f(rotationMatrixZ);

becomes

Quote:

temp = temp.Multiply33f(rotationMatrixZ);


Multiplying the X, Y and Z matrix now gives rotation around all three axes. And the same rotation matrix can be used for the vertex normals so the lighting model is correct as well now.

I'm aware that rotation can be done all in one calculation and the code you posted is useful David. I can understand how it works, and I say I understand the principle of matrices and quaternions for rotation. I just tried to break the problem down into something simpler to solve it.

Awesome guys. You made my Easter! I hope the easter bunny treats you both. :)




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS