Jump to content

  • Log In with Google      Sign In   
  • Create Account


Assimp Skeleton Bind Pose


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
10 replies to this topic

#1 Saad Manzur   Members   -  Reputation: 195

Like
0Likes
Like

Posted 21 March 2014 - 04:00 PM

I am trying to render my skeleton's bind pose in DirectX. But when I follow this code I end up having a distorted mesh.

void Bones::UpdateNode(const aiNode *pNode, const XMFLOAT4X4 parentMatrix) //Bone Index, Parent Matrix (Transformation)
{
	const char *name = pNode->mName.C_Str();
	XMFLOAT4X4 temp;
	AItoXM(pNode->mTransformation, temp);
	XMMATRIX NodeTransformation = XMLoadFloat4x4(&temp);

	XMMATRIX finalTransform = NodeTransformation * XMLoadFloat4x4(&parentMatrix);

	if (mBoneInfoMap.find(name) != mBoneInfoMap.end())
	{
		int boneID = mBoneInfoMap[name];
		XMMATRIX temp2 = XMLoadFloat4x4(&m_GlobalInverseTransform) * finalTransform * XMLoadFloat4x4(&mBoneInfo[boneID].toParent);
		XMStoreFloat4x4(&mBoneInfo[boneID].Transform, temp2);
	}

	XMFLOAT4X4 temp3;
	XMStoreFloat4x4(&temp3, finalTransform);

	for (int i = 0; i < pNode->mNumChildren; i++)
	{
		UpdateNode(pNode->mChildren[i], temp3);
	}
} 

What is the offset matrix provided by Assimp. And is the transformation matrix really the transformation with reference to it's parent. Is it necessary to calculate all the way from the root node of the scene ?



Sponsor:

#2 Waaayoff   Members   -  Reputation: 769

Like
2Likes
Like

Posted 23 March 2014 - 03:51 AM

It's been a long time since i looked at my animation code but i found this comment:

 

"Turns out Assimp generates animations relative to the parent joint, NOT the joint itself. So i don't have to multiply the animation transformation by the local transformation. Which i only use if there is no animation for a bone.."

 

Along with this code: (It's used for animation rather than getting the bind pose but since the bind pose is usually the first frame of animation, it should be similar to what you're looking for)

// pJoint->mAnimatedTransf is initialized with Assimp's local transform (which you can find like this: g_Scene->mRootNode->FindNode(bone_name)->mTransformation)
	// Then it can be replaced per frame by an interpolated animation transformation for every bone that has an animation
	// pJoint->mOffsetTransf you can find in an aiBone struct
	// DO NOT FORGET TO TRANSPOSE when you load them

	D3DXMATRIX final = pJoint->mAnimatedTransf  *  P;

 	//mFinalTransforms contains the matrices that will be sent to the shader
	mFinalTransforms.push_back( pJoint->mOffsetTransf * final );

From Assimp's documentation:  "Its [bone's] offset matrix declares the transformation needed to transform from mesh space to the local space of this bone."

 

i.e. it's the inverse bind pose.


"Spending your life waiting for the messiah to come save the world is like waiting around for the straight piece to come in Tetris...even if it comes, by that time you've accumulated a mountain of shit so high that you're fucked no matter what you do. "

#3 Saad Manzur   Members   -  Reputation: 195

Like
0Likes
Like

Posted 23 March 2014 - 08:17 AM


// DO NOT FORGET TO TRANSPOSE when you load them

 

So I have to transpose the offset matrix to get the bind pose ?


D3DXMATRIX final = pJoint->mAnimatedTransf * P;

 

Is 'P' the parent's transform matrix ?



#4 Waaayoff   Members   -  Reputation: 769

Like
1Likes
Like

Posted 23 March 2014 - 10:18 AM


Waaayoff, on 23 Mar 2014 - 10:51 AM, said:

// DO NOT FORGET TO TRANSPOSE when you load them
 
So I have to transpose the offset matrix to get the bind pose ?

 

No. From what i remember, this comment was there to remind me to transpose the offset matrix because of the difference between the matrix order between Assimp and DX. Try it with and without transposing and see which one is correct.

 

 

 



Waaayoff, on 23 Mar 2014 - 10:51 AM, said:

D3DXMATRIX final = pJoint->mAnimatedTransf * P;
 
Is 'P' the parent's transform matrix ?

 

Yes. This is the whole function. It will be called with the skeleton's Root bone and an identity matrix.

//=====================================================================================================
// Recursively calculate the joints' combined transformations
//=====================================================================================================
void AnimationController::CombineTransforms(Joint* pJoint, const D3DXMATRIX& P)
{
	  D3DXMATRIX final = pJoint->mAnimatedTransf  *  P;

	  mFinalTransforms.push_back( pJoint->mOffsetTransf * final );

	  for (unsigned i = 0; i < pJoint->mChildren.size(); i++)
	  {
			 CombineTransforms(pJoint->mChildren[i], final);
	  }

Where, like i mentioned above, pJoint->mAnimatedTransf should contain the local transformation if you want to get the bind pose.


Edited by Waaayoff, 23 March 2014 - 10:25 AM.

"Spending your life waiting for the messiah to come save the world is like waiting around for the straight piece to come in Tetris...even if it comes, by that time you've accumulated a mountain of shit so high that you're fucked no matter what you do. "

#5 Saad Manzur   Members   -  Reputation: 195

Like
0Likes
Like

Posted 24 March 2014 - 08:14 AM

Thanks to you, I have gotten this far.. But the mesh is still distorted..

 

distorted2_zps46dc1a32.png

 

Here is my code :

 

void Bones::UpdateNode(const aiNode *pNode, const XMFLOAT4X4 parentMatrix) //Bone Index, Parent Matrix (Transformation)
{
	const char *name = pNode->mName.C_Str();
	XMFLOAT4X4 temp;
	AItoXM(pNode->mTransformation, temp);
	XMMATRIX NodeTransformation = XMLoadFloat4x4(&temp);

	XMMATRIX finalTransform = XMLoadFloat4x4(&parentMatrix) * NodeTransformation;

	if (mBoneInfoMap.find(name) != mBoneInfoMap.end())
	{
		int boneID = mBoneInfoMap[name];
		if (mBoneInfo[boneID].meshdata)
		{
			XMMATRIX temp2 = finalTransform * XMLoadFloat4x4(&mBoneInfo[boneID].offsetMatrix);
			XMStoreFloat4x4(&mBoneInfo[boneID].Transform, temp2);
		}
		else
		{
			XMStoreFloat4x4(&mBoneInfo[boneID].Transform, XMMatrixIdentity());
		}
	}

	XMFLOAT4X4 temp3;
	XMStoreFloat4x4(&temp3, finalTransform);

	for (int i = 0; i < pNode->mNumChildren; i++)
	{
		UpdateNode(pNode->mChildren[i], temp3);
	}
}

aiNode->mTransformation is the local transform right ? And transpose does not work for me. This is the closest to what I got. I am passing the scene's root node. Your help is greatly appreciated. 



#6 Buckeye   Crossbones+   -  Reputation: 3805

Like
1Likes
Like

Posted 24 March 2014 - 10:16 AM

First: I'm not sure what "meshdata" is, so I don't know if it makes a difference.

 

However, if a bone is found in mBoneInfoMap, is it an error condition if that bone's meshdata is NULL or FALSE?

 

Also, the code you posted is apparently for some class or object Bones::. Does that function, in fact, iterate the entire node structure? That is, do you calculate the final transform for every node in the hierarchy?


Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.


#7 Saad Manzur   Members   -  Reputation: 195

Like
0Likes
Like

Posted 24 March 2014 - 02:20 PM


First: I'm not sure what "meshdata" is, so I don't know if it makes a difference.

 

It's just a flag if the bone has a mesh around it or not. Because in my model, not every bone is used for the mesh (Like Bind_HeadTopEnd) this bone is not used , I guess this bone is given to bind some helmet or other static meshes with it. 
 


Does that function, in fact, iterate the entire node structure?

 

I guess so, because I provide the root node as paremeter's to the funtion. It should visit each node in the SCENE not in the FRAME only, I guess. 

 

Help me understand this multiplications:(Thinking out loud)

 

 


XMMATRIX finalTransform = XMLoadFloat4x4(&parentMatrix) * NodeTransformation;

 

This transforms the child bone's position with respect to it's parent locally.

 

 

 


XMMATRIX temp2 = finalTransform * XMLoadFloat4x4(&mBoneInfo[boneID].offsetMatrix)

 

And this transforms the previous local transform into bind pose . (where offset matrix is said to be inverse bind pose matrix)

I am wrong right ?

 

Edit : If you observe the screen shot you will see that the hand is not the only thing that is distorted. The hip too.


Edited by Saad Manzur, 24 March 2014 - 02:36 PM.


#8 Saad Manzur   Members   -  Reputation: 195

Like
0Likes
Like

Posted 24 March 2014 - 03:56 PM

Ok , thanks guys I have solved it . Buck, Waaayoff and IceBreaker all of you , thanks for feedback. The thing is that I had to transpose the finalTransfromation matrix . It is still slightly distorted. It was even when I fed the identity matrices. Now for the animation part. Does it get easier or harder from here ?

bindPose_zps64675505.png



#9 Buckeye   Crossbones+   -  Reputation: 3805

Like
1Likes
Like

Posted 24 March 2014 - 06:14 PM


Saad Manzur, on 24 Mar 2014 - 10:14 AM, said:


XMMATRIX finalTransform = XMLoadFloat4x4(&parentMatrix) * NodeTransformation;


This transforms the child bone's position with respect to it's parent locally.

Well, sort of. In that particular function, because you start at the root and work through the hierarchy, each node passes on its mesh-space transform to its children. So when a child multiplies it's local "to parent" transform times it's parent's mesh-space transform, that forms the bone's bone-space-to-mesh-space transform.

 

 

 


Saad Manzur, on 24 Mar 2014 - 10:14 AM, said:

XMMATRIX temp2 = finalTransform * XMLoadFloat4x4(&mBoneInfo[boneID].offsetMatrix)


And this transforms the previous local transform into bind pose . (where offset matrix is said to be inverse bind pose matrix)

Nope. The final transform is not a "local" transform. It transforms from bone-space to mesh-space. The offset matrix transforms from mesh-space to bone-space. As mentioned in my article (you really should read through it, it may help), when a vertex is multiplied by temp2 (as you have it above) the vertex (which is in mesh-space) is transformed to bone-space (by the offset matrix), and then transformed from bone-space to mesh-space by the final transform part of it. When you use the pose mode locat transforms to do all that, the temp2 matrix you have above should end up as an identity matrix.

 

 

 


The thing is that I had to transpose the finalTransfromation matrix

 

That's likely because all your frame transforms appear to be column-major, judging by the order of the matrix multiplications. The shader likely expects row-major matrices which is accomplished by transposing.


Edited by Buckeye, 24 March 2014 - 06:16 PM.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.


#10 Saad Manzur   Members   -  Reputation: 195

Like
0Likes
Like

Posted 25 March 2014 - 10:43 AM

Thanks for your feedback. But the mesh is still distorted. I guess a vertex in the hand region does not have weight and bone index attached to it. I have to check it.

Do you know how to export complex animations from maya in dae format ? 



#11 Buckeye   Crossbones+   -  Reputation: 3805

Like
0Likes
Like

Posted 25 March 2014 - 12:25 PM


Do you know how to export complex animations from maya in dae format ?

I personally don't. Anyone else?


Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS