As an exercise I'm implementing my own vector / matrix library and using it in scene rendering. I'm using OpenGL and the intention is to have a GL-compatible storage layout. My matrix data is a float 2-d array indexed in row-major addressing. To make sure my generated matrices match the expected GL layout I use GLM ( http://glm.g-truc.net ) to generate equivalent matrices and compare the 16 consecutive floating point elements in memory at the starting address to make sure they're identical (within some epsilon), and all my tests succeed so far. Now for concatenating transforms, I use pre-multiplication with my row-major matrices, which should be identical to post-multiplication with column-major matrices ( see http://www.opengl.org/discussion_boards/showthread.php/167648-Matrix-stacks-and-post-multiplication?p=1182985#post1182985 for more details). I test that against GLM too and again it succeeds. In other words, if I have a GLM transformation matrix and a GLM projection matrix along with my own transform and projection matrices then the 16-element floating point memory layout of GLM_projection * GLM_transform is identical to the layout of My_transform * My_projection. Till this point everything works fine, and I can successfully upload the matrices to GLSL programs (I make sure that the transpose flag is false, so data isn't transposed by the GL driver) and use them for rendering just fine.
Now here's my problem: I'm loading Collada files with scene nodes having parent-child relationships. Now for a given node the world transform matrix should be equal to ParentTransform * LocalTransform, since I'm using row-major matrices and pre-multiply, correct? That doesn't seem to work however. Rotating the parent object seems to cause the children to rotate around their local origins, and not properly rotate while being parented to the object. Switching the order of the operation to LocalTransform * ParentTransform solves that problem.
Can someone explain this to me? I'm not merely interested in getting it to work, I want to find out the reason for this behavior - after all the whole thing is an exercise.