Dear community,
I started developing my own video game and my very own game engine some months ago. I made some good progress and I was able to realize everything I wanted so far. Sometimes I needed some online research, but I figured everything out after some time. Now, I am totally stuck. I do not know whether I did something wrong in my concept or if I am on the right path and I just have a minor bug. I am thankful for any help!
I wrote a C++ application, that is able to read FBX files (using Autodesks FBX SDK) and write all the information I need into a custom file format I designed for my game (engine). I am able to convert meshes, material and texture information and some more stuff into my file format and I can display all meshes properly in my game. I bought quite some stuff for the game and everything renders fine! Now, I want to extend my file format, the FBX file converter and my game engine to support skinned animations.
I read several online articels, like http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/how-to-work-with-fbx-sdk-r3582, http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/skinned-mesh-animation-using-matrices-r3577, book chapters, and many more and I think I understand the concept.
Data structures
I have added a new data structure for joints. Each joint has a name, stores its local transformation (translation, rotation, scaling) and has a set of children joints. Each of my mesh's vertices has a set of weighted links to joints.
So, every vertex knows the joints which affect the vertex's position including their weights. And each joint knows his place in the skeleton hierarchy (parent joint / children joints) and its local transformation.
What I wanted to do
I have already read and converted the Animation Stack including all Key Frames in the FBX file. However, before starting with the animation itself, I wanted to be able to show the model in its initial pose. I imported the FBX file in Unity first to make sure, that the FBX file is valid and to know how the initial pose looks like.
How I tried to do it
Every vertex in my mesh has a set of weighted links to joints. I wanted to calculate the vertex's position of the initial pose in a local world matrix I called JointPosition. Each vertex has its own JointPosition which is calculated using the weighted links (see below). Finally, I calculate the position of the vertex like this in my vertex shader:
struct VS_IN
{
float4 pos : POSITION;
float4 col : COLOR;
float2 TextureUV : TEXCOORD0;
matrix anim : INSTANCE;
};
PS_IN VS(VS_IN input)
{
PS_IN output = (PS_IN)0;
output.col = input.col;
output.TextureUV = input.TextureUV;
// Calculate position.
matrix w = transpose(mul(input.anim, World));
matrix v = transpose(View);
matrix p = transpose(Projection);
matrix mat = mul(w, v);
mat = mul(mat, p);
output.pos = mul(input.pos, mat);
return output;
}
anim is the calculated JointPosition and p is the vertex's position which was read from the FBX file.
As far as I understood, the Transformation Link Matrix contains the local position information for each joint (with FBX SDK: currCluster->GetTransformLinkMatrix(transformLinkMatrix);). I store the translation, rotation and scaling vector of this Transformation Link Matrix in every joint.
In order to calculate the JointPosition of a vertex, I use:
SharpDX.Matrix matrix = new SharpDX.Matrix(0.0f);
foreach (var jointLink in JointLinks)
matrix += jointLink.CalculateMatrix();
JointPosition = matrix;
Where each joint link multiplies its weight with joint's world matrix:
public SharpDX.Matrix CalculateMatrix()
{
return Weight * Joint.CalculateMatrix();
}
I use the following code to calculate joint's world matrix. I create the world matrix by multiplying the scaling, rotation and translation matrices using the vectors I got from the FBX files. The if-statement is required since some nodes have an invalid scaling vector. If a joint has a parent, I multiply its world matrix with its parent's world matrix, because the movement of a joint affects the position of all sub-joints.
SharpDX.Vector4 t = LinkTranslation;
SharpDX.Vector4 r = LinkRotation;
SharpDX.Vector4 s = LinkScaling;
if (s.X == 0.0f && s.Y == 0.0f && s.Z == 0.0f)
return SharpDX.Matrix.Identity;
SharpDX.Matrix result = Helper.Converters.ToMatrix(t, r, s);
if (Parent != null)
result = SharpDX.Matrix.Multiply(result, Parent.CalculateMatrix());
return result;
What I got
Well, the result looks pretty messed-up. :'-(
If I replace the last source code fragment with the Identity matrix, I see my mesh with the default pose, i.e. in a pose which is not affected by the joints of the mesh.
I thought I understood the concept of Skinned Animation, but I must have messed up something, because the result looks like a large blurry junk pile.