util::CMatrix m;
m.setTranslation(0.0f, 0.0f, -5.0f);
util::CMatrix r1;
util::CMatrix r2;
util::CMatrix r3;
// create a transformation node, with a translation matrix
scene::CTransformationNode* node = new scene::CTransformationNode(m, engine->getSceneManager() );
r1.setRotationXDegrees( 0.05f );
r2.setRotationYDegrees( 0.05f );
r3.setRotationZDegrees( 0.05f );
float temp2 = 0.0f;
while( engine->run() ){
driver->beginScene(); // clears the window with glClear
glLoadIdentity();
/*
glTranslatef(0.0f, 0.0f, -5.0f);
temp2 += 0.05f;
glRotatef(temp2, 1.0f, 0.0f, 0.0f);
glRotatef(temp2, 0.0f, 1.0f, 0.0f);
glRotatef(temp2, 0.0f, 0.0f, 1.0f);
*/
node->multMatrix(r1); // rotate by 0.05 degrees on X
node->multMatrix(r2); // rotate by 0.05 degrees on Y
node->multMatrix(r3); // rotate by 0.05 degrees on Z
engine->getSceneManager()->render();
driver->endScene(); // actually renders the window
}
🔒 Locked
Matrix multiplication
Advertisement
Original Post
Okay, what am I doing wrong? The matrix multiplication is the problem. Am I able to multiply like this? Because the commented-out gl functions and my multMatrix don't act the same as my multMatrix functions. Are rotation matricies cumulative like this? Even if the matrix starts out as a translation matrix and then get multiplied by rotation matrices? Because I was doing the same thing in 2d (but only one axis), and I was getting the proper result. Edit:: So, if I had a rotationX matrix rotated by 10 degrees, and I multiplied that by another rotationX matrix rotated by 15 degrees, would the final matrix be rotated around the X axis by 25 degrees?
c2_0 may be right about multiplication order, but there are some other things about your example that are a little unclear. For example, the gl code increases the angle each frame, but the code you're using appears to always rotate by a (possibly unnoticable) .05 degrees. Unless, perhaps node->multMatrix() accumulates the rotation? In any case, you might post multMatrix(), as it's not clear from the context what it does.
Quote:Minor detail, but multiplication order is actually determined by whether you're using row or column vectors, not whether the matrices are row or column major.
if row major:
M = T * M
if column major:
M = M * T
Quote:
Original post by Endar
Okay, what am I doing wrong?
It would be easier to tell if you post your matrix code. c2_0 might be right, but there could be other problems with it (for example the rotation matrix construction functions)...
Tom
EDIT: wow, did it really take me 9 minutes two write 2 lines? Anyway, what jyk said :)
Some of the relevant code:
Note:: The matrix is row-major, but is then transposed, immediately before multiplying by the glMultMatrixf (or whatever it's called) function.
CMatrix functions:
I think that should be all of the relevant code.
Note:: The matrix is row-major, but is then transposed, immediately before multiplying by the glMultMatrixf (or whatever it's called) function.
class CTransformationNode : public ISceneGraphNode{protected: util::CMatrix m_matrix; ///< The 4x4 matrix to hold the transformation for the nodepublic: /** * Constructor */ CTransformationNode(const util::CMatrix& m, scene::ISceneManager* smgr) : ISceneGraphNode(smgr), m_matrix(m) { } /** * Copy constructor */ CTransformationNode(const CTransformationNode& n) : ISceneGraphNode(n), m_matrix(n.m_matrix) { } /** * Apply the transformation of the node. */ virtual void render() { // FIXME - 9-09-05 - re-write this function and video driver to eliminate the gl func calls here glMatrixMode(GL_MODELVIEW_MATRIX); glPushMatrix(); // push a matrix onto the top of the model matrix stack // apply the node's transform to the model matrix m_sceneManager->getVideoDriver()->transform(video::MODEL_MATRIX, m_matrix); ISceneGraphNode::render(); // render all the child nodes glPopMatrix(); // pop matrix from the stack } /** * Multiply a matrix by the transformation matrix of the node. * \param m A const reference to a CMatrix object. */ void multMatrix(const util::CMatrix& m) { m_matrix *= m; }};/** * Perform a transform on a matrix. * \param m The matrix you want to transform * \param mat A CMatrix object which you want to transform the selected matrix by, */void COpenGLDriver::transform(MatrixType m, const util::CMatrix& mat){ float mtx[16]; mat.convertToOpenGL(mtx); switch(m){ case MODEL_MATRIX: glMatrixMode(GL_MODELVIEW); glMultMatrixf(mtx); break; default: break; } // FIXME: finish learning about the necessary matrices // and transforms and finish writing - 6/09/05}CMatrix functions:
class CMatrix{private: float matrix[4][4];};/** * Copies a transpose of this matrix into the array * pointed to by 'mtx'. * \param mtx An array of floats, at least 16 (floats) in size. */void CMatrix::convertToOpenGL(float* mtx) const{ CMatrix mat(*this); mat.transpose(); memcpy(mtx, mat.matrix, sizeof(float)*16);// copy transposed matrix into 'mtx'}/** * Sets 'this' matrix to the translation matrix, given 3 floats. * \param x The x component of the translation matrix. * \param y The y component of the translation matrix. * \param z The z component of the translation matrix. */void CMatrix::setTranslation(float x, float y, float z){ setIdentity(); matrix[0][3] = x; matrix[1][3] = y; matrix[2][3] = z;}/** * Sets 'this' matrix to a rotation matrix. The rotation is about the Z axis. * \param deg The radian value to rotate the matrix about the Z axis. */void CMatrix::setRotationZ(float rad){ setIdentity(); matrix[0][0] = (float)cos(rad); matrix[0][1] = (float)-(sin(rad)); matrix[1][0] = (float)sin(rad); matrix[1][1] = (float)cos(rad);}/** * Converts the degrees parameter to a radian value and then calls CMatrix::setRotationZ * to set the rotation matrix. * \param deg The degrees value to set the rotation matrix around the Z axis */void CMatrix::setRotationZDegrees(float deg){ setRotationZ( (float)(deg*PI) / 180.0f );}/** * Sets 'this' matrix to a rotation matrix. The rotation is about the X axis. * \param deg The radian value to rotate the matrix about the X axis. */void CMatrix::setRotationX(float rad){ setIdentity(); matrix[1][1] = (float)cos(rad); matrix[1][2] = (float)-(sin(rad)); matrix[2][1] = (float)sin(rad); matrix[2][2] = (float)cos(rad);}/** * Converts the degrees parameter to a radian value and then calls CMatrix::setRotationX * to set the rotation matrix. * \param deg The degrees value to set the rotation matrix around the X axis */void CMatrix::setRotationXDegrees(float deg){ setRotationX( (float)(deg*PI) / 180.0f );}/** * Sets 'this' matrix to a rotation matrix. The rotation is about the Y axis. * \param deg The radian value to rotate the matrix about the Y axis. */void CMatrix::setRotationY(float rad){ setIdentity(); matrix[0][0] = (float)cos(rad); matrix[0][2] = (float)sin(rad); matrix[2][0] = (float)-(sin(rad)); matrix[2][2] = (float)cos(rad);}/** * Converts the degrees parameter to a radian value and then calls CMatrix::setRotationY * to set the rotation matrix. * \param deg The degrees value to set the rotation matrix around the Y axis */void CMatrix::setRotationYDegrees(float deg){ setRotationY( (float)(deg*PI) / 180.0f );}/** * Overloaded *= operator. * \param o A const reference to a CMatrix object. * \return A reference to 'this' CMatrix object. */CMatrix& CMatrix::operator*=(const CMatrix& o){ // Temp vars CMatrix& t = *this; // Create a new matrix as a copy of this one CMatrix m(*this); // Multiply matricies - each row of first by each column of second // First row t(0,0)= m(0,0)*o(0,0) + m(0,1)*o(1,0) + m(0,2)*o(2,0) + m(0,3)*o(3,0); t(0,1)= m(0,0)*o(0,1) + m(0,1)*o(1,1) + m(0,2)*o(2,1) + m(0,3)*o(3,1); t(0,2)= m(0,0)*o(0,2) + m(0,1)*o(1,2) + m(0,2)*o(2,2) + m(0,3)*o(3,2); t(0,3)= m(0,0)*o(0,3) + m(0,1)*o(1,3) + m(0,2)*o(2,3) + m(0,3)*o(3,3); // Second row t(1,0)= m(1,0)*o(0,0) + m(1,1)*o(1,0) + m(1,2)*o(2,0) + m(1,3)*o(3,0); t(1,1)= m(1,0)*o(0,1) + m(1,1)*o(1,1) + m(1,2)*o(2,1) + m(1,3)*o(3,1); t(1,2)= m(1,0)*o(0,2) + m(1,1)*o(1,2) + m(1,2)*o(2,2) + m(1,3)*o(3,2); t(1,3)= m(1,0)*o(0,3) + m(1,1)*o(1,3) + m(1,2)*o(2,3) + m(1,3)*o(3,3); // Third row t(2,0)= m(2,0)*o(0,0) + m(2,1)*o(1,0) + m(2,2)*o(2,0) + m(2,3)*o(3,0); t(2,1)= m(2,0)*o(0,1) + m(2,1)*o(1,1) + m(2,2)*o(2,1) + m(2,3)*o(3,1); t(2,2)= m(2,0)*o(0,2) + m(2,1)*o(1,2) + m(2,2)*o(2,2) + m(2,3)*o(3,2); t(2,3)= m(2,0)*o(0,3) + m(2,1)*o(1,3) + m(2,2)*o(2,3) + m(2,3)*o(3,3); // Fourth row t(3,0)= m(3,0)*o(0,0) + m(3,1)*o(1,0) + m(3,2)*o(2,0) + m(3,3)*o(3,0); t(3,1)= m(3,0)*o(0,1) + m(3,1)*o(1,1) + m(3,2)*o(2,1) + m(3,3)*o(3,1); t(3,2)= m(3,0)*o(0,2) + m(3,1)*o(1,2) + m(3,2)*o(2,2) + m(3,3)*o(3,2); t(3,3)= m(3,0)*o(0,3) + m(3,1)*o(1,3) + m(3,2)*o(2,3) + m(3,3)*o(3,3);return *this;}I think that should be all of the relevant code.
First, from your setTranslation function it looks like your matrix is column major, not row major.
Also, if I remember correctly, OpenGL uses row major layout of matrices in memory, it's only the documentation which uses column major notation. I might be wrong on this, since I don't usually use OpenGL.
Lastly, you'd probably want to concatinate the matrices in the opposite order to perform local transformations.
Also, if I remember correctly, OpenGL uses row major layout of matrices in memory, it's only the documentation which uses column major notation. I might be wrong on this, since I don't usually use OpenGL.
Lastly, you'd probably want to concatinate the matrices in the opposite order to perform local transformations.
Quote:Just a couple of random points and clarifications...
First, from your setTranslation function it looks like your matrix is column major, not row major.
Also, if I remember correctly, OpenGL uses row major layout of matrices in memory, it's only the documentation which uses column major notation. I might be wrong on this, since I don't usually use OpenGL.
The OP's setTranslation() function indicates that he's using column vectors, not that the matrix is column major. In fact, he's using 2d indexing, which clouds the issue of majorness somewhat. It happens that 2d c++ arrays are stored in row-major format, a fact the OP relies on in his memcpy() call. To ensure portability of code and consistency from platform to platform, it's a good idea to represent your matrix internally using a 1d rather than 2d array. This gives you complete control over the majorness and any related issues.
Confusing row/column vectors and row/column-major is a common mistake, one which I also made when I was first learning this material. Getting these two concepts clear in your mind early on will save you trouble down the line.
Also, OpenGL usus column-major rather than row-major format. It also uses column vectors, so it happens that the layout in memory is identical to that of a DirectX matrix. However, the code for multiplying OpenGL and DirectX matrices, as well as the order of operations, is different - the similarity in layout is really just incidental and shouldn't be invested with too much meaning.
I didn't look over all the code, but given the variables of majorness and vector convention, there are a lot of ways to get things wrong. Worse yet, two mistakes will often cancel each other out, so it's possible to have working code that is still incorrect :-)
Okay, well, I'm now re-writing my matrix class for a 1D array. Is there anything specific way I have to write it to insure that it is row-major or column-major?
And I'm going to keep the vectors as rows, instead of columns, and do a simple transpose when I need to interact with OGL.
And I'm going to keep the vectors as rows, instead of columns, and do a simple transpose when I need to interact with OGL.
Quote:Just remember how the matrix is laid out in memory. Here's a matrix with 2d indexing:
Okay, well, I'm now re-writing my matrix class for a 1D array. Is there anything specific way I have to write it to insure that it is row-major or column-major?
[00 01]
[10 11]
The row-major form would be:
[0 1]
[2 3]
Column-major:
[0 2]
[1 3]
In code it's generally more intuitive to work with 2d indexing. One way to do this is to write an inline function that converts from 2d to 1d, something like:
private: float m_data[16]; float& m_(unsigned int i, unsigned int j) { return m_data[i*4+j]; }That example would be for row major. For column major, you'd use i+j*4.Quote:Are you going to be using this class primarily with OpenGL? If so, why not just simplify things and use column vectors for consistency?
And I'm going to keep the vectors as rows, instead of columns, and do a simple transpose when I need to interact with OGL.
Let me know if you need more info.
What happens if you use an identity transformation node. (ie one with no translation, an identity matrix) and use the following code rather?
Does it work this way?
node->multMatrix(m); // translate by (0,0,-5)node->multMatrix(r1); // rotate by 0.05 degrees on Xnode->multMatrix(r2); // rotate by 0.05 degrees on Ynode->multMatrix(r3); // rotate by 0.05 degrees on ZDoes it work this way?
Oh, and, just quickly, before this thread is mostly done and buried, if I wanted to do a translation, then a rotation, then another translation, or a scale, or pretty much any combination of any of them, in any order, to get the final matrix, would I have to keep three matrices, like a translation matrix, which is the final matrix of all of the translations, a rotation matrix, which is the final of all the rotations, etc, and then just before rendering, multiply those three in a specific order to get the final model matrix?
Edit:: Frey: Do you mean having those 4 lines inside the rendering loop? Because that is where the three multMatrix(r*) are. And wouldn't that just move the object further and further along the -z axis? Or were you asking if it works at all?
Well, I just tried it, and, no. It doens't work. I actually don't see anything, and I'm waaay too tired to get on this now. I'll have to leave it till saturday. But thanks [smile]
Edit:: Frey: Do you mean having those 4 lines inside the rendering loop? Because that is where the three multMatrix(r*) are. And wouldn't that just move the object further and further along the -z axis? Or were you asking if it works at all?
Well, I just tried it, and, no. It doens't work. I actually don't see anything, and I'm waaay too tired to get on this now. I'll have to leave it till saturday. But thanks [smile]
Quote:
Original post by Endar
Oh, and, just quickly, before this thread is mostly done and buried, if I wanted to do a translation, then a rotation, then another translation, or a scale, or pretty much any combination of any of them, in any order, to get the final matrix, would I have to keep three matrices, like a translation matrix, which is the final matrix of all of the translations, a rotation matrix, which is the final of all the rotations, etc, and then just before rendering, multiply those three in a specific order to get the final model matrix?
Yes:
Quote:
MSDN for more info
One reason order is significant is that transformations like rotation and scaling are done with respect to the origin of the coordinate system. Scaling an object that is centered at the origin produces a different result than scaling an object that has been moved away from the origin. Similarly, rotating an object that is centered at the origin produces a different result than rotating an object that has been moved away from the origin.
Unless you want your user to be aware of this ordering, it is important. Note that if you do this, it will be impossible to express rotation around its own axis and rotation around a remote axis at the same time on a single object. You will need a separate parent node to express the rotation around the remote axis, as is common in all Scene Graph libraries I know...
Tom
Okay, I've figured out that it looks like some of my translation/rotation functions are for column vectors and others for row-vectors.
Since I'm not sure which are which, could someone point me to a site which explcitly gives me either one? (a lot of the sites I've googled show the matrices, but don't give much of a hint as to whether they are for row or column vectors)
Since I'm not sure which are which, could someone point me to a site which explcitly gives me either one? (a lot of the sites I've googled show the matrices, but don't give much of a hint as to whether they are for row or column vectors)
Quote:This is true, and can be frustrating. Quite often, a tutorial will just assume a convention without ever conveying it to the reader.
(a lot of the sites I've googled show the matrices, but don't give much of a hint as to whether they are for row or column vectors)
One thing you can do is look for any examples in the text that give it away. For example, if you see something like:
v' = T*R*v
You're dealing with column vectors, whereas if you have:
v' = v*R*T
You have row vectors. Another giveaway is where the translation vector is, as that is unambiguous. For scale matrices it's irrelevant; for projection and rotation it can be hard to tell unless you're familiar with the structure.
I can't think of a particular reference which explains the difference in a clear way. If you have particular functions that you're not sure about, you could post them.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement