Hi. I want to implement bone animation in my engine and I faced with the issue that when I multiply all bone matrices and set them to shader, my model is disassembling.
As far as I understood the theory correct, I need multiply bind shape matrix on inverse bind matrix for each bone * key frame matrix for current bone and then go throught the bones hierarhy and multiply each chld bone matrix on parent bone matrix. Then I need to pass the result as matrix array to shader and multiply each position with corresponding final joint matrix * joint weight and then do standart multiplication on World, View, Projection amtrices. That shoud be all, but my implementation is not eorking although I double checked my matrices and all other data. I think problem is in matrices, but I cannot find where exactly.
Here is my method for matrix calculation. Could someone tell me what I am doing wrong here? Maybe I am missing something.
private Matrix[] JointMatrices;
private int counter = 0;
private void CalculateInterprolation(AnimationControllerComponent controller, AnimationComponent animation, Dictionary<ulong, Entity> entities)
{
JointMatrices = new Matrix[controller.JointDictionary.Count];
Dictionary<string, Matrix> final = new Dictionary<string, Matrix>();
foreach (var inverseBindMatrixName in controller.JointDictionary)
{
//multiply bind shape * inverse bind * key frame matrix
Matrix finalMatrix = controller.BindShapeMatrix * inverseBindMatrixName.Value * animation.Animations[inverseBindMatrixName.Key].Matrices[counter];
final.Add(inverseBindMatrixName.Key, finalMatrix);
}
if (counter > animation.Animations.Count - 1)
{
counter = 0;
}
Stack<Joint> joints = new Stack<Joint>();
joints.Push(animation.SkeletonList[0]);
while (joints.Count > 0)
{
Joint currentJoint = joints.Pop();
if (final.ContainsKey(currentJoint.JointName))
{
if (currentJoint.Parent != null)
{
//multiply child * parent joint matrix
final[currentJoint.JointName] = final[currentJoint.JointName]* final[currentJoint.Parent.JointName];
}
}
foreach (var joint in currentJoint.Children)
{
joints.Push(joint);
}
}
int index = 0;
//copy final matrices to matrix array for setting it to shader
foreach (var matrix in final)
{
JointMatrices[index] = matrix.Value;
index++;
}
var renderSystem = (RenderSystem)EntityWorld.SystemManager.GetSystems<RenderSystem>()[0];
var matrixArray = renderSystem.customEffect.GetVariableByName("jointsArray").AsMatrix();
//set final matrix array to shader
matrixArray.SetMatrix(JointMatrices);
}
Shader code:
matrix jointsArray[10];
...
float4 pos = float4(0,0,0,0);
// Change the position vector to be 4 units for proper matrix calculations.
input.position.w = 1.0f;
//Bone1
pos += mul(jointsArray[input.jointIndices.x], input.position)*input.jointWeights.x;
//Bone2
pos += mul(jointsArray[input.jointIndices.y], input.position)*input.jointWeights.y;
//Bone3
pos += mul(jointsArray[input.jointIndices.z], input.position)*input.jointWeights.z;
//Bone4
pos += mul(jointsArray[input.jointIndices.w], input.position)*input.jointWeights.w;
// Calculate the position of the vertex against the world, view, and projection matrices.
output.position = pos;
output.position = mul(output.position, worldMatrix);
output.position = mul(output.position, viewMatrix);
output.position = mul(output.position, projectionMatrix);
Before calling that method I have model on image 1 and after - on image 2.
P.S. I am using managed DX 11 with sharpdx .