   [SOLVED] Skeletal animation rotation problems
  I'm trying to render COLLADA animation exported from Blender. My test animation moves a human's hand up and left. I got the basic skinning working fine, but the animation rotates to the wrong direction. The animation is split to 4 animations: translate, rotateX, rotateY and rotateZ. I assume that I must combine those values to form a key frame's joint matrix and I must multiply it with the joint's parent's world matrix and store the result to joint's world matrix. Here's some code:Methods from Mesh class:/** * Applies matrices to skeleton. Should start from the root node. * Joint's world transformation is parent's world transformation * local trans. **/void applySkin( Joint* joint ){    assert( joint );    for (size_t c = 0; c < joint->children.size(); ++c) {   Math::multiplyMatrix( joint->children[ c ].transform,joint->worldTransform,joint->children[ c ].worldTransform );   applySkin( &joint->children[ c ] );    }}// Replaces joint named "name"'s transform matrix with matrix. Should start searching from root.    void replaceJointMatrix( const std::string& name, Joint* j, float matrix[ 16 ] )    {   assert( j );   assert( matrix );   if (name == j->name) {  for (int i = 0; i < 16; ++i) { j->transform = matrix;  }  <span class="cpp-keyword">return</span>;   }   <span class="cpp-keyword">else</span> {  <span class="cpp-keyword">for</span> (size_t c = <span class="cpp-number">0</span>; c &lt; j-&gt;children.size(); ++c) { replaceJointMatrix( name, &amp;j-&gt;children[ c ], matrix );  }   }    }    <span class="cpp-comment">// Animations change rotX, rotY, rotZ, posX, posY and posZ. From these values the new joint transform matrix is constructed.</span>    <span class="cpp-keyword">void</span> applyAnimation()    {   <span class="cpp-keyword">for</span> (std::map&lt; std::string, Animation &gt;::iterator a = animations.begin(); a != animations.end(); ++a) {  <span class="cpp-comment">// Skips this animation if it's not running.</span>  <span class="cpp-keyword">if</span> (a-&gt;second.stepStartTime == <span class="cpp-number">0</span>) { <span class="cpp-keyword">continue</span>; }  <span class="cpp-comment">// If true, proceed to the next time step.</span>  <span class="cpp-keyword">if</span> ((SDL_GetTicks() - a-&gt;second.stepStartTime) / <span class="cpp-number">1000</span>.0f &gt;= a-&gt;second.input[ a-&gt;second.inputIndex ]) { ++a-&gt;second.inputIndex; a-&gt;second.stepStartTime = SDL_GetTicks();  }  <span class="cpp-comment">// If true, the animation is finished.</span>  <span class="cpp-keyword">if</span> (a-&gt;second.inputIndex == (<span class="cpp-keyword">int</span>)a-&gt;second.input.size()) { animations.erase( a-&gt;first ); <span class="cpp-keyword">continue</span>;  }  Joint joint;  findJoint( a-&gt;second.joint, &amp;skeleton[ <span class="cpp-number">0</span> ], &amp;joint );  <span class="cpp-keyword">float</span> t = (SDL_GetTicks() - a-&gt;second.stepStartTime) / <span class="cpp-number">1000</span>.0f;  <span class="cpp-keyword">int</span> ind = a-&gt;second.inputIndex;  t /= a-&gt;second.input[ ind ];  <span class="cpp-keyword">float</span> animRotationMatrix[ <span class="cpp-number">16</span> ];  Math::identityMatrix( animRotationMatrix );  <span class="cpp-keyword">if</span> (a-&gt;second.operation == <span class="cpp-literal">"translate"</span>) { <span class="cpp-keyword">float</span> xv = (a-&gt;second.output[ ind - <span class="cpp-number">1</span> == -<span class="cpp-number">1</span>? <span class="cpp-number">0</span> : (ind - <span class="cpp-number">1</span>)*<span class="cpp-number">3</span>+<span class="cpp-number">0</span> ]); posX = interpolate( xv, a-&gt;second.output[ ind * <span class="cpp-number">3</span> + <span class="cpp-number">0</span> ], t ); <span class="cpp-keyword">float</span> yv = (a-&gt;second.output[ ind - <span class="cpp-number">1</span> == -<span class="cpp-number">1</span>? <span class="cpp-number">1</span> : (ind - <span class="cpp-number">1</span>)*<span class="cpp-number">3</span>+<span class="cpp-number">1</span> ]); posY = interpolate( yv, a-&gt;second.output[ ind * <span class="cpp-number">3</span> + <span class="cpp-number">1</span> ], t ); <span class="cpp-keyword">float</span> zv = (a-&gt;second.output[ ind - <span class="cpp-number">1</span> == -<span class="cpp-number">1</span>? <span class="cpp-number">2</span> : (ind - <span class="cpp-number">1</span>)*<span class="cpp-number">3</span>+<span class="cpp-number">2</span> ]); posZ = interpolate( zv, a-&gt;second.output[ ind * <span class="cpp-number">3</span> + <span class="cpp-number">2</span> ], t ); Math::makeRotationMatrix4x4( animRotationMatrix, rotX, rotY, rotZ ); <span class="cpp-keyword">float</span> transMatrix[ <span class="cpp-number">16</span> ]; Math::identityMatrix( transMatrix ); transMatrix[ <span class="cpp-number">3</span> ] = posX; transMatrix[ <span class="cpp-number">7</span> ] = posY; transMatrix[<span class="cpp-number">11</span> ] = posZ; Math::multiplyMatrix( transMatrix, animRotationMatrix, animRotationMatrix ); replaceJointMatrix( a-&gt;second.joint, &amp;skeleton[ <span class="cpp-number">0</span> ], animRotationMatrix );  } <span class="cpp-comment">// Output values are changing X angle.</span>  <span class="cpp-keyword">if</span> (a-&gt;second.operation == <span class="cpp-literal">"rotateX.ANGLE"</span>) { <span class="cpp-keyword">float</span> val1 = a-&gt;second.output[ ind - <span class="cpp-number">1</span> == -<span class="cpp-number">1</span>? <span class="cpp-number">0</span> : ind - <span class="cpp-number">1</span> ]; <span class="cpp-keyword">float</span> val2 = a-&gt;second.output[ ind ]; rotX = interpolate( val1, val2, t ); Math::makeRotationMatrix4x4( animRotationMatrix, rotX, rotY, rotZ ); <span class="cpp-keyword">float</span> transMatrix[ <span class="cpp-number">16</span> ]; Math::identityMatrix( transMatrix ); transMatrix[ <span class="cpp-number">3</span> ] = posX; transMatrix[ <span class="cpp-number">7</span> ] = posY; transMatrix[<span class="cpp-number">11</span> ] = posZ; Math::multiplyMatrix( transMatrix, animRotationMatrix, animRotationMatrix ); replaceJointMatrix( a-&gt;second.joint, &amp;skeleton[ <span class="cpp-number">0</span> ], animRotationMatrix );  }<span class="cpp-comment">// Y and Z-angles are changed the same way, no need to paste them here.</span>   vertexDeformed.clear();   applySkin( &amp;skeleton[ <span class="cpp-number">0</span> ] );   <span class="cpp-comment">// Applies the deform.</span>   <span class="cpp-comment">// From COLLADA spec: outv = sum{ (v * BSM) * IBMi * JMi * JW }</span>   <span class="cpp-keyword">for</span> (size_t v = <span class="cpp-number">0</span>; v &lt; influences.size(); ++v) {  Influence&amp; i = influences[ v ];  vertexDeformed.push_back( Vector() );  Vector4 temp;  Vector4 v4 = Vector4( vertex[ v ].x, vertex[ v ].y, vertex[ v ].z, <span class="cpp-number">1</span>.0f );  Math::vectorMultMatrix4x4( v4, bindShapeMatrix, &amp;temp ); <span class="cpp-comment">// v * BSM</span>  <span class="cpp-keyword">for</span> (size_t j = <span class="cpp-number">0</span>; j &lt; i.jointIndices.size(); ++j) { <span class="cpp-comment">// Finds a joint for this influence.</span> std::string jointName = jointArray[ i.jointIndices[ j ] ]; Joint joint; findJoint( jointName, &amp;skeleton[ <span class="cpp-number">0</span> ], &amp;joint ); Vector4 temp2; Math::vectorMultMatrix4x4( temp, joint.ibm, &amp;temp2 ); <span class="cpp-comment">// * IBMi</span> Vector4 temp3; Math::vectorMultMatrix4x4( temp2, joint.worldTransform, &amp;temp3 ); <span class="cpp-comment">// * JMi</span> temp3 *= weights[ i.weightIndices[ j ] ]; <span class="cpp-comment">// * JW</span> vertexDeformed.back() += Vector( temp3.x, temp3.y, temp3.z ); <span class="cpp-comment">// outv</span>  }   }    }</pre></div><!–ENDSCRIPT–>I noticed that if I manually change a joint's translation (joint.transform[3, 7 and 11] ) nothing seems to change. From the rendered animation I think that my animation's pivot point is wrong.edit: I solved this problem. Solution in the last post.<!–EDIT–><span class=editedby><!–/EDIT–>[Edited by - EngineCoder on May 29, 2010 6:33:16 AM]<!–EDIT–></span><!–/EDIT–>
  Does your game use the same coordinate system as blender? (Up:Z Right:X Out:+Y)You might try to describe the situation more specifically than "it rotates in the wrong direction", that's kind of vague.   ;Quote:Original post by karwostsDoes your game use the same coordinate system as blender? (Up:Z Right:X Out:+Y)You might try to describe the situation more specifically than "it rotates in the wrong direction", that's kind of vague.My code uses Y-up, but swapping Y and Z in the rotation code does not make it right. Also I have checked Y-up in Blender's armature properties.I'll post some screenshots tomorrow to describe how it looks and how it should look.   ;  I finally got it working, after trying to find the problem for a week! I had to transpose the matrices that came with the COLLADA file and I had to use negative rotation angles.   