Advertisement

Skeletal animation (ASSIMP) formula

Started by May 19, 2020 06:36 PM
11 comments, last by evelyn4you 4 years, 8 months ago

I am trying to implement skeletal animation in my engine using ASSIMP. So far I have the model loading and rendering fine.. I am pretty sure the per-vertex inputs are set up correctly with the proper bone IDs and blend weights, and I think the shader itself is correct.

The basic problem I think is I have an incomplete understanding of the use of the transformation matrices to generate the final bone matrix. ASSIMP provides key frames made up of positions, rotations and scaling factors. There is also a “bone offset matrix” provided, which is also called the inverse bind pose matrix.

So i am currently doing something like this in my app(directX):

matBone=matTranslate*matRotation; //OK to leave out scaling because no scaling keys?
final matrix= matBoneOffset * matBone;

I am also concatenating the matBone matrix with its parent bone matrices up to the root …this seems necessary because I dont think the position keys are concatenated. i dont know… i've been reading lots of posts and articles…much of it is confusing me because of different conventions and so on..What i really need is a clear procedure that works in directX so i can see if my data is correct, or the problem lies elsewhere… Not looking for code so much and a clear formula.. thanks


		//is root
		if (myBones[i].isroot)
		{
			myBones[i].mat = matBoneTransform;
		}

		else
		{
			myBones[i].mat = myBones[myBones[i].parentIndex].mat *  matBoneTransform;
		}

		myBones[i].mat = myBones[i].mat * myBones[i].matOffset;

After some work I've come up with this method, but still not working correctly…everything seems warped still…Don't know what I'm missing.. In some posts I see reference to some “global transform”, but I'm not sure what this means…

Advertisement

Matt_Aufderheide said:
In some posts I see reference to some “global transform”, but I'm not sure what this means…

I would assume that global transform refers to the transformation matrix of the skeletal root/base/placement joint in the world.

Just use the world origin and don't worry about the global transform until you get the basic skeleton working. You can use the identity matrix or just ignore it completely.

🙂🙂🙂🙂🙂<←The tone posse, ready for action.

Ok, thanks.
Right now the thing I'm most unsure of is how and when to use the “matOffset” which is described as the inverse bone pose matrix…

Matt_Aufderheide said:
inverse bone pose matrix

I'm almost sure that would be similar to a view matrix for a camera. The inverse bone pose matrix just sets the joint back to the bind pose if it has been previously transformed.

Thanks BTW, now I'm inspired to go back and work on my skeletal animation system.

🙂🙂🙂🙂🙂<←The tone posse, ready for action.

Thanks. Now I've got to the point where I think I've everything correct EXCEPT all the animated bones seem to be scaled in some uniform way that's wrong…The actual joints and angles look right. This is what i have so far

  //is root
 if (myBones[i].parentIndex >= 255)
 {
  myBones[i].matWorld = matLocal;
 }

else
{
  myBones[i].matWorld = matLocal *   myBones[myBones[i].parentIndex].matWorld;
}

 finalarray.matBones[i] = XMMatrixTranspose(myBones[i].matWorld * off);
Advertisement

@Matt_Aufderheide The global transform might have scaling information that the child joints inherit. Are you saying the mesh and the skeleton are different sizes?

🙂🙂🙂🙂🙂<←The tone posse, ready for action.

While the vertices affected by the root bone seems fine, all the rest of the vertices are scaled with what appears to be some linear fashion… the actual mesh and bones are all the same size when not transformed…

I just don't know what this “global transform” might be or where to get it from the ASSIMP data…

Still banging my head against this…
Let me describe my basic understanding of the process, and maybe someone can see where I'm going wrong.

0) start in bind pose
1)Transform the root bone by the local transformation matrix (translation, rotation, scaling)
2) work down the chain transforming each child bone by local transform and parent transform.
3) When done then multiply the final transform with the Offset matrix..
4) send the matrix array to the shader …

Since this isnt working for me, I assume I'm wrong, and I've tried so many combinations of transposing, order of operations, etc.. I'm at a loss

After a lot of fiddling I've solved some of the issues… the joints are all connected now and not stretched out like before…but now everything seems to be at the wrong angle :( here is my code so far, do this for every bone from top to bottom if anyone is interested.

//UINT j is current bone index
aiMatrix4x4 matTransformation = scene->mRootNode->FindNode(myBones[j].name)->mTransformation;
aiMatrix4x4 matRot=(aiMatrix4x4)scene->mAnimations[i]->mChannels[j]->mRotationKeys[q].mValue.GetMatrix();

//is root bone
if (j == 0)
	myBones[j].matNode[q] =
 //store the transform here
	matTransformation *
  //node->mTransformation
	matRot;
 //derived from key frame

else
	myBones[j].matNode[q] =
	myBones[myBones[j].parentIndex].matNode[q] *
 //parent node transform if the bone is not root
	matTransformation *
	matRot;
					
aiMatrix4x4 matLocal =
	(myBones[j].matNode[q] *
	mesh->mBones[j]->mOffsetMatrix).Transpose();
 //transform final matrix (this is actually global)

myBones[j].matFrame[q] = (
						XMMATRIX(matLocal.a1, matLocal.a2, matLocal.a3, matLocal.a4,
							matLocal.b1, matLocal.b2, matLocal.b3, matLocal.b4,
							matLocal.c1, matLocal.c2, matLocal.c3, matLocal.c4,
							matLocal.d1, matLocal.d2, matLocal.d3, matLocal.d4));

This topic is closed to new replies.

Advertisement