• ### Announcements

GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Followers 0

# Rotation Matrix

## 3 posts in this topic

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]; }
0

##### Share on other sites
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 > voidmatrix_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 );}
0

##### Share on other sites
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
0

##### Share on other sites
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. :)
0

## Create an account

Register a new account