.x file skinning problem

Started by
3 comments, last by dpadam450 8 years, 7 months ago

Well, i read lots of articles and codes for the skinning (and animation) of .x file.

But i still can't make it right

Let me show some information i have learned first.( Please tell if i am wrong )

(1) Let's forget the animation now, only skinning

There're 3 key datas:

1. FrameTransformMatrix (bones and other Frames)

2. BoneOffsetMatrix

3. Vertex Positions, bone indices, weights

(2) The formulas for calculating ( OpenGL order ):

1. BoneCombinedTransformMatrix = RootFrameTransformMatrix * ... * ParentBoneTransformMatrix * CurrentBoneTransformMatrix

My file data looks like this:

[attachment=29058:hierarchy.png]

2. SkinnedPosition = BoneCombinedTransformMatrix * BoneOffsetMatrix * VertexPosition

Then i get the "Rest Pose" model skinned right

[attachment=29059:cat_rest.png]

OK, everything seems good yet.

But when i export the .x file in "Bind Pose", the problem comes out

In Blender, the "Bind Pose":

[attachment=29060:cat_bind_pose_blender.png]

In my app, becomes...

[attachment=29061:cat_bind_pose.png]

Well, i thought it must be the exporter's bug, so i load it in a .x MeshViewer, it's perfect...

So i tried to figure out the relations between all these datas, but my math is bad..

i analyze the structure in blender:

[attachment=29064:struct.png]

after i done lots of matrix calculations, then i have this...

[attachment=29062:bad_1.png]

and this...

[attachment=29063:bad_2.png]

and so on...

i also picked one animation data to multiply with, but it just going more crazy...

Is that something missing in the formula?

I read others code, but still can't find the key point, they seems just use the formulas above...

please help~~thanks~

Advertisement

I wrote my own animation exporter in blender for my engine. One thing that blows it up, is if there is any rotation applied to the mesh or the armature. Make sure those both have no rotation before digging in. If it has rotation, you unparent the mesh to the armature, you can use something like tools->Apply Scale and Rotation.

Until this equation here equal the identity matrix for all bones, then obviously you need to debug it. Bolded part should be wrong. I'll have to look later but I believe you need to apply the root bone or the inverse root bone transform, BEFORE you apply the currentBone transform.

BoneCombinedTransformMatrix = RootFrameTransformMatrix * ... * ParentBoneTransformMatrix * CurrentBoneTransformMatrix

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

thank you dpadam450. i follow your idea Apply Scale and Rotation for meshes, then the meshes and animations mess up... Even if it could work, i may not be able to modify every models in this way. The directx sdk works well with it, maybe we just need a little more calculation? Or can you give a little information about your exporter?

The best piece of advice I can give you is to simplify the example you are using.

Create a Model with just two or three bones, maybe just two cylinders that are connected at a right angle.

This way you can more easily debug the information.

Your issue may be that you are not in openGL coordinates, or not applying the keyframe animation by the inverse bind pose.

Animation is always buggy to figure out at first.

This is the line of code I use to compute my final matrix for a given frame at load time.

1.) I store position and rotation separate. I don't remember why.

2.) .x will be in Blender coordinates which are DirectX coordinates, not OpenGL

My Blender (DirectX) to openGL matrix is this, and the inverse of this is just simply the Transpose (look up matrix transpose if you don't know what it is, its simple).

[1 , 0, 0, 0]
[0 , 0, 1, 0]
[0 , -1, 0, 0]
[0, 0, 0, 0]

*(bone->Animation_Frames[j]) = frame_translate*bind_pose_translate*inv_to_GL*(*bone->Animation_Frames[j])*inv_Bind_Pose*to_GL*inv_translate;

So I translate to bone to the origin 0,0,0 by applying the inverse of the bones bind pose position, I apply the to openGL matrix, so that all the next stuff applied will be in openGL coordinates from here on. Then I take the inverse of the bind pose (again just the transpose of the rotation no position). This is applied because the animation frames are in bone space, not global space, so they must be applied relative to the bone. So I have to apply the current animatino frame relative to the original bind pose. Next the animation frame is multiplied. Then I apply the inverse to openGL because the next 2 final matrices for translation are in openGL space. I export positions already in openGL space that is why I do that. I then apply "bind_pose_translate" which now takes that rotated bone right back to where it lives at the bind pose. Finally if the bone has moved this frame I apply the frame translation for the bone.

I believe the position and rotation separation was due to simplicity and debugging. Eventually you will find something that works. But this is what I did.

NOTE: the final computed matrix for the bind pose, should be the identity matrix for all bones. To test this, animation_Frame* inverse_bind_pose should be the identity matrix. And why?...... because the matrix for the bind pose, and an animation frame that is literally the bind pose, means those 2 matrices are identical, and multiplying a matrix by its inverse, is the Identity matrix. IE input vertices did not move.

I'm in and out on here anymore so you can PM me but that is about it. Make sure you get the identity and you should be fine.

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

This topic is closed to new replies.

Advertisement