• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
bobhowdy

Proper order of operations for skinning

5 posts in this topic

I'm using a .x (direct x) model file exported from Blender. It contains the mesh, armature and animation data for my model. I can get the model to render properly in its bind pose. I'm trying to animate it now. However, no matter what I try, I can't get the model to transform properly when rendering an animation pose. It's all deformed.

I created a simple object that is simply two bones and a cuboid. It looks like an elbow joint of an arm sticking straight up in the air. I have the following matrices:


Root (Contains everything) = rootMatrix
Cube (Contains the entire model) = modelMatrix
Armature (Contains the two bones) = armatureMatrix
Armature_RootBase (Root "upper arm" bone)
SkinMatrix_RootBase (The skin matrix for the root bone)
Armature_TipTop (is the "forearm" bone)
SkinMatrix_TipTop (The skin matrix for the second bone)

When loading the model in, I transform all the vertices by the bind matrix to have the bind pose as the default. I get the bind matrix with:

[CODE]
Matrix4f bindMatrix = new Matrix4f();
Matrix4f.mul(bindMatrix, rootMatrix, bindMatrix);
Matrix4f.mul(bindMatrix, modelMatrix, bindMatrix);
[/CODE]



That works great. The bind pose is exactly as it should be, how it's shown in Blender.

Now when I try to animate is where the problems come in. I'm using GLSL to apply the bone matrices to the vertices. When I send identity matrices for all the bones it works fine. I've done tests and I know the GLSL is working and sending the matrices and applying the bones to the correct vertices. The main problem is I don't know how to properly get the matrices.

[b]I have a bind pose model and I need to take a rotation, translation and scale and create the proper matrix to transform the model.[/b]

I'll explain my current non-working process, because it might just need a little tweak to make it work.

I have structures to mimic the structure of the armature. At the moment I'm exporting full animations from Blender (I'll work out interpolation later), so I have a key frame for every frame. I can apply an animation to a model and I'm able to lookup the animation rotation, translation and scale for any bone.

Basically I go through and calculate the new bone matrices, then send them to my shader to be applied to the bones. So the update process goes like this:


Starting with the root bone

UpdateFinalTransform(Bone)
calculateAnimationTransform()
foreach child bone
UpdateFinalTransform(child)

Where calculateAnimationTransform() looks like this:

[CODE]
transformMatrix.setIdentity();
combinedMatrix.setIdentity(); //clear the transform and animation matrices

Matrix4f bindMatrix = new Matrix4f(getBindMatrix()); //get the bind matrix for this model
Matrix4f.mul(transformMatrix, (Matrix4f)bindMatrix.invert(), transformMatrix); //multiply by the inverted bind matrix
Matrix4f skinMatrix = getSkinWeightMatrix(); //get the skin matrix for this bone

Matrix4f animationTransform = new Matrix4f();
//rotate, scale, translate

animationTransform.applyQuaternion(new Quaternion(rotation));
tmpMatrix.setIdentity();
tmpMatrix.m00 = scale.x;
tmpMatrix.m11 = scale.y;
tmpMatrix.m22 = scale.z;
Matrix4f.mul(animationTransform, tmpMatrix, animationTransform);
tmpMatrix.setIdentity();
tmpMatrix.m30 = position.x;
tmpMatrix.m31 = position.y;
tmpMatrix.m32 = position.z;
Matrix4f.mul(animationTransform, tmpMatrix, animationTransform);
setCombinedMatrix(animationTransform); //set the animation transform for this bone, so that children bones can access it

combinedMatrix = getTransformMatrix(); //get the combined transform of this animation transform * parent animation transform
Matrix4f finalMatrix = Matrix4f.mul(skinMatrix, combinedMatrix, null); //skin the combined matrix
Matrix4f.mul(finalMatrix, transformMatrix, transformMatrix); //apply the inverted bind pose
Matrix4f.mul((Matrix4f)bindMatrix.invert(), transformMatrix, transformMatrix); //undo the inverted bind pose

[/CODE]

each bone has that getTransformMatrix() method that looks like this:

[CODE] if (parent == null) {
return Matrix4f.mul(combinedMatrix, parentArmature.getArmatureRootMatrix(), null);
} else {
return Matrix4f.mul(combinedMatrix, parent.getCombinedMatrix(), null);
}[/CODE]

combinedMatrix is set to its default armature matrix if an animation matrix is not defined.


So my questions.

1. Am I creating the animationTransform properly?
2. Is this the correct order of transforms?
3. What am I missing?
4. How do I do it properly? Edited by bobhowdy
0

Share this post


Link to post
Share on other sites
Edit as I missed a section of your post and ended up misreading the question as a result.

I'm not sure why you have a seperate "skinMatrix" and "transformMatrix" being applied to the animation:

[indent=1]Export your vertex data [b]post-transformed[/b], so that the model looks correct when skinned with identity matricies.

Export the [b]inverse [/b]of the [b]worldspace bind pose [/b]for each joint.
This matrix is used to bring the vertex back into local space as necessary.

At runtime, the skinning matrix is the [u]animated worldspace matrix multiplied by the inverse-bind-pose matrix[/u].
If the worldspace matrices match the original bind pose, you get identity matrices and so your model is correct. If you move the joints around, you will see the mesh move correctly.[/indent]

The local-space animation matrix is built by composing a rotation matrix from the quaternion (which should just end up being the top left 3x3), multiplying the topleft 3x3 by the scale components (no need to multiply the bottom row or right column) then setting the translation row (or column depending on whether your matrices are transposed) You are better off writing the matrix manually instead of multiplying in the data:



On the note of inverse bind pose matrices, the big reason to stick with storing the inverse bind pose and leaving the mesh data in transformed space on export is for multiple influences per vertex. If you were to transform the mesh into local space, it would be a unique local space per bone influence.

When dealing with multiple influences you can either run the vertex through each of the matrices separately, then blend the results, or blend the matrices together then multiply the vertex through it. There are other ways of doing this blending that give nicer results, less 'candy wrapping' etc, and are worth looking at once you have your core steps up and running. Edited by Digitalfragment
1

Share this post


Link to post
Share on other sites
Thanks for the response!

[quote]I'm not sure why you have a seperate "skinMatrix" and "transformMatrix" being applied to the animation:[/quote]

The .x file has a skinWeights section, in that it has a matrix, that's the skinMatrix I'm referring to. The transformMatrix is where I'm storing the result of all the matrix operations.

[quote]Export your vertex data post-transformed, so that the model looks correct when skinned with identity matricies.[/quote]
I'm doing that. If I set my bone matrices to identity, I get the model as it looks in Blender.

[quote]Export the inverse of the worldspace bind pose for each joint.[/quote]
Is the worldspace bind pose the same as the bind pose used to transform the vertices to get the "post-transformed vertex data"? i.e. The matrix obtained by rootMatrix*modelMatrix? If so the bind pose is the same for each joint... so I don't understand.

So you're saying the animation matrix should be created like the following?

[CODE] Matrix4f animationTransform = new Quaternion(rotation).toMatrix();
animationTransform.m00 *= scale.x;
animationTransform.m01 *= scale.x;
animationTransform.m02 *= scale.x;

animationTransform.m10 *= scale.y;
animationTransform.m11 *= scale.y;
animationTransform.m12 *= scale.y;

animationTransform.m20 *= scale.z;
animationTransform.m21 *= scale.z;
animationTransform.m22 *= scale.z;

animationTransform.m30 = position.x;
animationTransform.m31 = position.y;
animationTransform.m32 = position.z;[/CODE]


Where does the armatureMatrix and parent animation transforms come into play?

I know that

[CODE]
Matrix4f.mul(transformMatrix, boneMatrix, transformMatrix);
Matrix4f.mul(transformMatrix, skinMatrix, transformMatrix);
[/CODE]

Results in the identity matrix. But if I multiply in the animationTransform from above, things get wonky. I made an animation that's just the bind pose. But the animationTransform is not the identity matrix when the model is in the bind pose, so what's the deal? Edited by bobhowdy
0

Share this post


Link to post
Share on other sites
[quote name='bobhowdy' timestamp='1349149363' post='4985939']
[quote]Export the inverse of the worldspace bind pose for each joint.[/quote]
Is the worldspace bind pose the same as the bind pose used to transform the vertices to get the "post-transformed vertex data"? i.e. The matrix obtained by rootMatrix*modelMatrix? If so the bind pose is the same for each joint... so I don't understand.
[/quote]
The worldspace bindpose matrix for a bone is the the world space matrix for that bone itself in blender. If you only have local space matrices for the bones in blender, then you have to work up the tree from the root node to generate them.

[quote name='bobhowdy' timestamp='1349149363' post='4985939']
So you're saying the animation matrix should be created like the following?

[CODE] Matrix4f animationTransform = new Quaternion(rotation).toMatrix();
animationTransform.m00 *= scale.x;
animationTransform.m01 *= scale.x;
animationTransform.m02 *= scale.x;

animationTransform.m10 *= scale.y;
animationTransform.m11 *= scale.y;
animationTransform.m12 *= scale.y;

animationTransform.m20 *= scale.z;
animationTransform.m21 *= scale.z;
animationTransform.m22 *= scale.z;

animationTransform.m30 = position.x;
animationTransform.m31 = position.y;
animationTransform.m32 = position.z;[/CODE]


Where does the armatureMatrix and parent animation transforms come into play?
[/quote]
That animationTransform matrix is the local-space matrix generated by a single frame of animation, relative to the space of the parent.
The parent animation transforms come into play when generating the world transform for the parent, as its the world transform of the parent you need to pass down to the children in the tree.

The armatureMatrix in your case might be a pre-concatenation matrix for the animation transform?
I've never needed anything beyond: parentBoneWorldspace * childAnimatedLocalspace * inverseBindPose

[quote name='bobhowdy' timestamp='1349149363' post='4985939']
I know that

[CODE]
Matrix4f.mul(transformMatrix, boneMatrix, transformMatrix);
Matrix4f.mul(transformMatrix, skinMatrix, transformMatrix);
[/CODE]

Results in the identity matrix. But if I multiply in the animationTransform from above, things get wonky. I made an animation that's just the bind pose. But the animationTransform is not the identity matrix when the model is in the bind pose, so what's the deal?
[/quote]
animationTransform is a local space matrix. When your animationTransforms are converted to world space by walking the tree and concatenating the transforms, the resulting matricies should look like the boneMatrix values. Unless your boneMatrix (and corresponding skinMatrix) are in a different coordinate space.

I suggest writing some debug rendering code that draws the matrices as axis-markers connected by lines showing the hierarchy.
1

Share this post


Link to post
Share on other sites
I'm still not getting this [img]http://public.gamedev.net//public/style_emoticons/default/sad.png[/img]

Lets try with some matrices. This is what I have to work with for the root bone:

root
1.0 0.0 0.0 0.0
0.0 0.0 1.0 0.0
0.0 1.0 -0.0 0.0
0.0 0.0 0.0 1.0

model
0.5 0.0 0.0 0.0
0.0 0.5 0.0 0.0
0.0 0.0 2.0 2.0
0.0 0.0 0.0 1.0

armature
2.0 0.0 0.0 0.0
0.0 2.0 0.0 0.0
0.0 0.0 0.5 -1.0
0.0 0.0 0.0 1.0

rootbone
1.0 0.0 0.0 0.0
0.0 0.0 -1.0 0.0
0.0 1.0 0.0 0.0
0.0 0.0 0.0 1.0

skin
0.5 0.0 0.0 0.0
0.0 0.0 2.0 2.0
0.0 -0.5 0.0 0.0
0.0 0.0 0.0 1.0

animation
0.0 -1.0 0.0 0.0
-1.0 0.0 0.0 0.0
0.0 0.0 -1.0 0.0
0.0 0.0 0.0 1.0

I know that root*model*armature*rootBone*skin results in the identity matrix. But I don't see anything here that would turn my animation matrix back into the identity matrix. It seems like it should be turned back into the identity matrix or the bind pose matrix.

My model is sort of a test model. It's the shape of two bones, the two bones that animate it. So I can see where the bones are easily. Edited by bobhowdy
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0