Jump to content
  • Advertisement
Sign in to follow this  
uglybdavis

CPU Skinning, mesh to joint space (Offset matrix)

This topic is 2178 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey guys, i'm trying to manually calculate a models offset matrix (Mesh to joint space). I came across some documents that this should just be the inverse of the bind pose. That is true, except for some formats seem to have a different offset matrix for each mesh. I have the mesh in world space, and the joint in world space. I'm trying to get a matrix that would let me do mesh to joint transforms.... Here is my code so far:

 

void Animation::SetInvBindPose(const Matrix& meshMatrix) {
	// meshMatrix is the world position of the mesh
	
   // Put the skeleton into bind pose   
   for (int i = 0; i < m_vSkeleton.size(); ++i) {
        Joint& joint = m_vSkeleton;
        Matrix localTransform =  Translation(joint.rotation, joint.translation);
        
        if (joint.parent == -1)
            joint.working = localTransform;
        else
            joint.working = Multiply(localTransform, m_vSkeleton[joint.parent].working);
    }
    
	// Multiply the mesh matrix by the inverse of each joints bind pose
    for (int i = 0; i < m_vSkeleton.size(); ++i) {
        Joint& joint = m_vSkeleton;
        joint.working = Multiply(meshMatrix, Inverse(joint.working));
    }
}

 

 

My matrices are right handed column major (OpenGL style) with the translation being in the bottom row.

 

I think this is a "simple" math issue, can anyone help? (PS, i've ortho-normalized the incoming mesh matrix)

 

 

Share this post


Link to post
Share on other sites
Advertisement

Yes, i am asking about the offset transform from that pdf.

 

I've tackled this from every which angle i can think of, but no luck....

 

My current implementation (The code above) is close. Any submesh modeled around origin is fine. But any submesh that has an offset keeps rendering wrong...

Edited by uglybdavis

Share this post


Link to post
Share on other sites

Drop your problem down to two bones in 2-d with no rotation and only a few vertices, draw a picture and work it on paper doing the arithmetic yourself.

 

Remember that in bind position the character is a continuous mesh that is modeled around some arbitrary (0,0,0) point. When you move certain vertices into a bone space, the bone is now the (0,0,0) point, so you need to create an offset matrix that correctly accounts for this so that the vertices surround the bone correctly.

Edited by Steve_Segreto

Share this post


Link to post
Share on other sites

That part works. if a mesh is modeled around origin i can display and animate it just fine.

 

Not all meshes are modeled around (0, 0, 0), in a .X file, some submeshes are modeled around the "character" submesh.

 

Compensating for these meshes is the problem. Going from this non-origin "mesh space" to bone space.

 

My current formula is MeshWorld * BoneWorld.Inverse(), but that fails pretty bad. I tried rationalizing it, but have hit a brick wall...

Share this post


Link to post
Share on other sites

You can still solve this with a simple 2-d drawing, just pick a vertex and work backward, give it a non-zero origin.

 

When you say a submesh is modeled around a "character" submesh, would a good example be like a HAT mesh on a character's HEAD mesh? Or is the problem you are having more with submeshes that have more than one parent transform above them (i.e. most meshes are children of the root transform, even if there is a skeleton transform hierarchy described elsewhere).

 

i.e.

 

Root Bone

     - Head Mesh

     - Pelvis Bone

         - Head Bone

             - Hat Mesh

Share this post


Link to post
Share on other sites

After working out my scenario on paper, i came up with this:

 

Inverse(joint.worldMatrix * Inverse(meshWorldMat))

 

Which yields the exact same result as the above :(

 

The problem in my case is a bow on the characters back. The way it is modelled the character is at (0, 0, 0) and the box is on his back. The character is under the root node, the bow is under root > biped > pelvis. the matrix i'm using as the "world" matrix of the bow (and character) is the mesh node's transform multiplied by the transform of every one of it's parents, so just world space for it.

Share this post


Link to post
Share on other sites

Let's just work with translation in one dimension (x). We assume that vertices are listed in bone space. Let:

 

root:   toParent = { x = 0 }      toRoot = { x = 0 }  InverseToRoot = { x = 0 }

biped: toParent = { x = -2 }     toRoot = { x = -2 } InverseToRoot = { x = 2 }

pelvis: toParent = { x = -3 }     toRoot = { x = -5 } InverseToRoot = { x = 5 }

 

Vertices under pelvis.

v0_boneSpace = { x = 4 }  v0_bindSpace = { x = 9 }        4 + Inverse(toRoot[Pelvis])

v1_boneSpace = { x = -3 } v1_bindSpace = { x = 2 }       -3 + Inverse(toRoot[Pelvis])

 

Vertices in Pelvis Bone Space

 

                       v1                                                                             v0

+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+

                       -3                                0(P)                                         4

 

Bones and Vertices in bind (root) space

 

                                                                                 v1                                                                              v0

+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+

                                                          0(R)                 2(B)                            5(P)                                         9             

 

 

finally remember that Bind Space != World Space         

Edited by Steve_Segreto

Share this post


Link to post
Share on other sites

Bare with me here, i think my math was correct the second time around.

 

This is what the static mesh (No bones or anything) looks like rendered:

1.png

 

Now i use the offset matrix assimp has provided me:

2.png

 

And finally, this is what it looks like with my offset matrix:

3.png

 

The thing i noticed here is the skeleton is not in bind pose.

Looking at the animation list, bind pose is not stored for this model.

 

So, the question now shifts to how do i get that pretty skeleton into bind pose? (Pretty sure i can math this out myself)

 

Unless i'm wrong and the issue is still with my offset matrix.....

Share this post


Link to post
Share on other sites

Why is image 1 shown slightly rotated instead of head-on? Why not use image 2, it looks ok?

 

Image 3 is screwed up, looks like the per-vertex skinning is wrong?

 

This is a rite of passage into 3d game programming, you need to knuckle down and just figure this out. Use Luna's document and your model and just try to reason about everything yourself. The offset transform is just for the vertices of a skin, not the bones.

 

If you render your scene hierarchy without vertices (just drop points at the center of each bone) and don't apply any animation keyframes, isn't the skeleton in bind position?

 

Can you attach the model file in assbin format? :) Just downloaded assimp.exe and assimp_view.exe

Edited by Steve_Segreto

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!