Caio Sabino
22Mar/10Off

Ragdoll Using Bullet Physics Engine

This article describes a simple approach on how to animate a skinned mesh with a limited number of bones using rigid bodies. The implementation uses a skinned mesh file created by the author. In the provided method, there is no need for any kind of bone hierarchy once we are dealing with meshes with low bones count. The author provides the full source code for a demo application, which also contains editing tools for providing external data for the ragdoll.

In this article, I am providing a simple and effective way of creating a ragdoll using Bullet Physics engine and linking it to a skinned mesh. Even though the idea can be applied to any skinned mesh file format, I used one of my own, which you can find a fully description here.

The code for the ragdoll itself is quite small and it needs values that should be provided for the user. Assuming we are dealing with skinned mesh that do not have too many bones (the one I used has 18), it shouldn't take more than a few minutes for the user to provide these values, also, the demo provides tools for tweaking them

Ragdolls are commonly used for simulating character animation that should react to the physical environment surrounding them, it is not practical to have animations generated by artists to achieve what we do with ragdolls. The video below shows the demo application I created.

Full source code here.

For obvious reasons, no artist can predict how the character should be animated on the environment above, since only during runtime the character will know what is affecting it's behavior (for example, the bullet trajectory on the demo).

So here is what it is needed to create a ragdoll:

1 - Create a simplified physical representation of the character.
2 - Update the skinned mesh bones according to the physical representation on runtime

Ragdoll's rigid bodies

For the first mentioned, the user should be responsible for providing data that will describe the ragdolls's physical representation, such as the rigid bodies dimensions and offsets, the constraints rotation axis and position offsets. All those attributes could also be calculated automatically during the ragdoll setup, and it probably should have if you are dealing with a great amount of bones, since that's not the case here, the code provides a few editing modes for tweaking those values. Finding a basic setup for the ragdoll shouldn't take more than a few minutes with this approach.

The first thing needed is to provide the rigid bodies dimensions, and tell which bones those bodies are going to be linked to. In Game.cpp, the rigid bodies dimensions are defined by calling the CreateShape method, passing the dimensions as arguments:

//creates the ragdoll parts
//pelvis
CreateShape(0,true,1.4f, 2.5f, 1.1f);
//head
CreateShape(1,true,0.7f, 0.8f, 0.8f);
//upper arms
CreateShape(2,false,0.4f, 1.1f, 0.5f);
CreateShape(3,false,0.4f, 1.1f, 0.5f);
//lower arms
CreateShape(4,false,0.5f, 1.6f, 0.4f);
CreateShape(5,false,0.5f, 1.6f, 0.4f);
//upperlegs
CreateShape(6,false,0.6f, 1.8f, 0.7f);
CreateShape(7,false,0.6f, 1.8f, 0.7f);
//lower leg
CreateShape(8,false,0.5f, 1.9f, 0.5f);
CreateShape(9,false,0.5f, 1.9f, 0.5f);

This only stores the values in arrays so we can later create the rigid bodies. We achieve that by calling the RagDoll method SetPart. This method is called on Game.cpp on the CreateRagDoll method. See the code below:

//sets up a part of the ragdoll
//int index = the index number of the part
//int setMeshBoneTransformIndex = the bone index that this part is linked to,
//float offsetX, float offsetY, float offsetZ = translatin offset for the part in bone local space
//float mass = part's mass,
//btCollisionShape * a_shape = part's collision shape
void RagDoll::SetPart(int index, int setMeshBoneTransformIndex, float offsetX, float offsetY, float offsetZ,float mass, btCollisionShape * a_shape)
{
	m_boneIndicesToFollow[setMeshBoneTransformIndex] = index;

	//we set the parts position according to the skinned mesh current position

	D3DXMATRIX t_poseMatrix = m_skinnedMeshContainer->GetPoseMatrix()[setMeshBoneTransformIndex];
	D3DXMATRIX *t_boneWorldRestMatrix = m_skinnedMesh->GetBoneWorldRestMatrix(setMeshBoneTransformIndex);

	D3DXMATRIX t_boneWorldPosition;
	D3DXMatrixMultiply(&t_boneWorldPosition, t_boneWorldRestMatrix, &t_poseMatrix);

	D3DXVECTOR3 * t_head = m_skinnedMesh->GetBoneHead(setMeshBoneTransformIndex);
	D3DXVECTOR3 * t_tail = m_skinnedMesh->GetBoneTail(setMeshBoneTransformIndex);				

	float tx = t_tail->x - t_head->x;
	float ty = t_tail->y - t_head->y;
	float tz = t_tail->z - t_head->z;

	//part's world matrix
	D3DXMATRIX *t_partMatrix = new D3DXMATRIX();
	*t_partMatrix = t_boneWorldPosition;

	D3DXMATRIX *t_centerOffset = new D3DXMATRIX();
	D3DXMatrixIdentity(t_centerOffset);
	D3DXMatrixTranslation(t_centerOffset, (tx / 2.0f) + offsetX, (ty / 2.0f) + offsetY, (tz/2.0f) + offsetZ);
	D3DXMatrixMultiply(t_partMatrix, t_partMatrix, t_centerOffset);

	D3DXVECTOR3 t_pos;
	D3DXVECTOR3 t_scale;
	D3DXQUATERNION t_rot;

	D3DXMatrixDecompose(&t_scale, &t_rot, &t_pos, t_partMatrix);

	btRigidBody* body = PhysicsFactory::GetInstance()->CreateRigidBody(mass,t_pos.x, t_pos.y, t_pos.z, t_rot.x, t_rot.y, t_rot.z, t_rot.w, a_shape);

	D3DXMATRIX t_partInverse;
	D3DXMatrixInverse(&t_partInverse, NULL, t_partMatrix);

	//puts the bone's matrix in part's local space, and store it in m_boneToPartTransforms
	D3DXMatrixMultiply(m_boneToPartTransforms[setMeshBoneTransformIndex], &t_boneWorldPosition, &t_partInverse);

	m_ragdollBodies[index] = body;

	delete t_partMatrix;
	t_partMatrix = NULL;

	delete t_centerOffset;
	t_centerOffset = NULL;

}


The picture above shows the relation between a bone and a rigid body. This offset transform is stored so that we can later update the bones position and still maintain that offset

The bone index is informed, and we use the bone rest matrix as a reference for the rigid body that is going to be create. Keep in mind that Bullet Physics rigid bodies usually have their pivot point in the center of the body, so we need to place the rigid body in the middle position of the bone, in addition to that, the user can provide some translation offsets. We first store the rigid body world position considering those offset translations in t_partMatrix:

*t_partMatrix = t_boneWorldPosition;

D3DXMATRIX *t_centerOffset = new D3DXMATRIX();
D3DXMatrixIdentity(t_centerOffset);
D3DXMatrixTranslation(t_centerOffset, (tx / 2.0f) + offsetX, (ty / 2.0f) + offsetY, (tz/2.0f) + offsetZ);
D3DXMatrixMultiply(t_partMatrix, t_partMatrix, t_centerOffset);

But the objective here is to store those offsets in the rigid body local space, so we can apply those offsets to the bones later, when the rigid bodies have updated their positions on the physic world. We do that in the code below:

//puts the bone's matrix in part's local space, and store it in m_boneToPartTransforms
D3DXMatrixMultiply(m_boneToPartTransforms[setMeshBoneTransformIndex], &t_boneWorldPosition, &t_partInverse);

Most likely, a ragdoll is going to have a few rigid bodies in comparison to the amount of bones in the skinned mesh. I have seen ragdoll codes that relies on bone hierarchy for calculating bones transforms that doesn't have a rigid body directly attached to it, traversing the hierachy tree and multiplying the bones matrices to come up with a final matrix. The approach in use here is quite simpler, there is no need to traverse the hierarchy, instead, the offset matrix is created as the SetPart method does, but taking a different bone as reference. We also keep track of the bones relations to the rigid bodies so that we can later retrieve the correct matrices, storing them at m_boneIndicesToFollow. This whole process is described in the RagDoll method SetBoneRelation. In this case, the user is responsible for passing correctly the bone relation, see example below:

//for the bones that have no direct part linked to, we inform which bone that has a linked part
//this bone should be following
m_ragdoll->SetBoneRelation(4,0);
m_ragdoll->SetBoneRelation(2,0);
m_ragdoll->SetBoneRelation(8,0);
m_ragdoll->SetBoneRelation(1,0);
m_ragdoll->SetBoneRelation(7,6);
m_ragdoll->SetBoneRelation(10,17);
m_ragdoll->SetBoneRelation(13,12);
m_ragdoll->SetBoneRelation(16,15);
void RagDoll::SetBoneRelation(int realBoneIndex, int followBoneIndex)
{
	//it is going to the same thing the setPart method does, but the bone it is going to take
	//as a reference is the one passed as followBoneIndex and the the part's matrix is below
	//by calling GetPartForBoneIndex. Still there is going to be a new entry in m_boneToPartTransforms
	//which is the bone transform in the part's local space
	int partToFollowIndex = GetPartForBoneIndex(followBoneIndex);

	m_boneIndicesToFollow[realBoneIndex] = partToFollowIndex;

	D3DXMATRIX t_poseMatrix = m_skinnedMeshContainer->GetPoseMatrix()[realBoneIndex];
	D3DXMATRIX *t_boneWorldRestMatrix = m_skinnedMesh->GetBoneWorldRestMatrix(realBoneIndex);

	D3DXMATRIX t_boneWorldPosition;
	D3DXMatrixMultiply(&t_boneWorldPosition, t_boneWorldRestMatrix, &t_poseMatrix);

	D3DXMATRIX *t_partMatrix = new D3DXMATRIX();
	btTransform t_partTransform = m_ragdollBodies[partToFollowIndex]->getWorldTransform();
	*t_partMatrix = BT2DX_MATRIX(t_partTransform);

	D3DXMATRIX t_partInverse;
	D3DXMatrixInverse(&t_partInverse, NULL, t_partMatrix);

	D3DXMatrixMultiply(m_boneToPartTransforms[realBoneIndex], &t_boneWorldPosition, &t_partInverse);		

	delete t_partMatrix;
	t_partMatrix = NULL;	

}

Bone relations

The image above shows the relations of 4 bones to a single rigid body.

Once the rigid bodies dimensions and offsets are set, we move on to the constraints. I am not going to give a full description of the constraints available on the Bullet Physics engine, you can find it here. In this demo, we use the cone twist and the hinge constraint, which should be enough for most humanoid shaped ragdolls. I have created a helper method for setting up the constraints local transforms, it is  the CalculateConstraintTransform method, available at Game.cpp.

void Game::CalculateConstraintTransform(int partAIndex, int partBIndex, float partAOffsetX, float partAOffsetY, float partAOffsetZ, float partBOffsetX, float partBOffsetY, float partBOffsetZ, float quatX, float quatY, float quatZ, float quatW,  btTransform * a_transform, btTransform *b_transform, int constraintIndex)
{
	btTransform t_bodyTransformA = m_ragdoll->GetRadollParts()[partAIndex]->getWorldTransform();
	D3DXMATRIX t_bodyAMtx = BT2DX_MATRIX(t_bodyTransformA);
	btTransform t_bodyTransformB = m_ragdoll->GetRadollParts()[partBIndex]->getWorldTransform();
	D3DXMATRIX t_bodyBMtx = BT2DX_MATRIX(t_bodyTransformB);

	D3DXVECTOR3 t_offsetA = D3DXVECTOR3(partAOffsetX, partAOffsetY, partAOffsetZ);
	D3DXVECTOR3 t_offsetB = D3DXVECTOR3(partBOffsetX, partBOffsetY, partBOffsetZ);

	//puts the translation offsets in world space
	D3DXVECTOR4 t_pointAVec;
	D3DXVECTOR4 t_pointBVec;
	D3DXVec3Transform(&t_pointAVec, &t_offsetA, &t_bodyAMtx);
	D3DXVec3Transform(&t_pointBVec, &t_offsetB, &t_bodyBMtx);

	//constraint origin in world space
	btVector3 t_pointA = btVector3(t_pointAVec.x,t_pointAVec.y,t_pointAVec.z);
	btVector3 t_pointB = btVector3(t_pointBVec.x,t_pointBVec.y,t_pointBVec.z);
	btVector3 t_constraintOrigin = btVector3(	t_pointA.x() + ((t_pointB.x() - t_pointA.x()) / 2.0f),
												t_pointA.y() + ((t_pointB.y() - t_pointA.y()) / 2.0f),
												t_pointA.z() + ((t_pointB.z() - t_pointA.z()) / 2.0f));

	//inside this if clause, the matrix for editing mode is setup up with the constraint world position
	//and rotation
	if(constraintIndex > -1)
	{

		g_testConstraintMatrix[constraintIndex] = new D3DXMATRIX();
		D3DXMatrixIdentity(g_testConstraintMatrix[constraintIndex]);

		D3DXMATRIX t_pos;
		D3DXMatrixIdentity(&t_pos);
		D3DXMatrixTranslation(&t_pos, t_constraintOrigin.x(), t_constraintOrigin.y(), t_constraintOrigin.z());

		D3DXMATRIX t_rot;
		D3DXMatrixIdentity(&t_rot);
		D3DXMatrixRotationQuaternion(&t_rot, &D3DXQUATERNION(quatX, quatY, quatZ, quatW));

//		D3DXMatrixMultiply(g_testConstraintMatrix[constraintIndex], g_testConstraintMatrix[constraintIndex], &t_pos);
		D3DXMatrixMultiply(g_testConstraintMatrix[constraintIndex], &t_rot, &t_pos);

	}

	//constraint world matrix
	btTransform t_constraintWorld;
	t_constraintWorld.setIdentity();
	t_constraintWorld.setOrigin(t_constraintOrigin);
	t_constraintWorld.setRotation(btQuaternion(quatX, quatY, quatZ, quatW));

	//puts the constraint in the local space of their corresponding parts
	a_transform->setIdentity();
	*a_transform = t_bodyTransformA.inverse() * t_constraintWorld;

	b_transform->setIdentity();
	*b_transform = t_bodyTransformB.inverse() * t_constraintWorld;

}

The reason I created this method, is because it is easier to visualize on the editors the connecting points of the constraints on the rigid bodies, rather then placing the joint in the correct position. First, we apply the rigid bodies world transform to the offset values, so that they are also in world space. Then, we calculate the middle point between those two connecting points, this is going to be the constraint world position. Then we need to put the constraint position in the rigid bodies local space, so that the Bullet Physics engine can simulate it properly. The constraint rotation axis is provided in the form of a quaternion
and it is applied in the constraint world matrix.

With all that, we conclude the set up of the physical representation of the ragdoll. The only thing we need now is to update the bones position in order to follow the ragdoll's rigid body.

We are going to do that on every frame update of the game on the Update method of Game.cpp. The code is simple:

int totalBones = m_ragdollMeshContainer->GetMesh()->GetTotalBones();
for(int i = 0; i < totalBones; i++) {	 	D3DXMATRIX * t_transform = m_ragdoll->GetBoneWorldTransform(i);
	m_ragdollMeshContainer->SetBoneTransform(t_transform, i);

}

It simply retrieves the world transform for a given bone from the ragdoll, and updates it on the skinned mesh. Here is how we calculate the bone world matrix from a ragdoll:

//This method will return the world position that the given bone should have
D3DXMATRIX * RagDoll::GetBoneWorldTransform(int boneIndex)
{
	//the part world matrix is fetched, and then we apply the bone transform offset to obtain
	//the bone's world position
	int t_partIndex = GetPartForBoneIndex(boneIndex);

	btTransform  t_transform = m_ragdollBodies[t_partIndex]->getWorldTransform();
	D3DXMATRIX t_partMatrix = BT2DX_MATRIX(t_transform);

	D3DXMatrixIdentity(m_bonesCurrentWorldPosition[boneIndex]);
	D3DXMatrixMultiply(m_bonesCurrentWorldPosition[boneIndex], m_boneToPartTransforms[boneIndex], &t_partMatrix);

	return m_bonesCurrentWorldPosition[boneIndex];
}

If the SetPart and SetBoneRelation has been clearly described, this method should look quite obvious. We fetch which rigid body the given bone should be following ( GetPartForBoneIndex(boneIndex) ), then we retrieve the rigid body's world matrix (m_ragdollBodies[t_partIndex]->getWorldTransform()), and finally we apply the previously calculated offset
( m_boneToPartTransforms[boneIndex] ) to the rigid body's world matrix, in order to maintain the offset, no matter what is the rigid body's position at the time.

That concludes the whole ragdoll creation and simulation process presented on the Demo.

About the Source Code

The source code provided here, is focused solely on the ragdoll. The rendering engine was developed by me some time ago, and it hasn't any kind of optimization. There are far more complex and better render engines available, proprietary or free. The objective here is to create a clean ragdoll implementation that can be plugged in easily. The whole ragdoll code presented here can be found on Game.cpp and Ragdoll.cpp classes, and that's all you need to create a similar example.

I used a male body model on the demo, which I simply lost track where I found it. I had to modify it a bit in order to meet the exporter requirements, and I also had to paint the vertices weight myself (in case you are wondering why sometimes you can see spiky corners on the mesh, I am not an artist). If you would like to try it with a different mesh, I would be glad to see it.

If you find this code useful, please refer to my website whenever you use it. If you feel like, you can donate to my paypal account on the right hand side.

Hope you enjoyed it. I sure did 🙂

References

Granberg, Carl, Character animation With Direct3D. Charles River Media, 2009.

Luna, Frank D. , Introduction to 3D Game Programming With DirectX 9.0c. Wordware Publishing Inc., 2006

Comments (7) Trackbacks (0)
  1. ” All those attributes could also be calculated automatically during the ragdoll setup, and it probably should have if you are dealing with a great amount of bones, since that’s not the case here, the code provides a few editing modes for tweaking those values. ”

    In fact this is usually precomputed and stored in the scene file. Methods to compute this based on the mesh vertices are really expensive (computationally). Some of the algorithms are explained in

    http://www.amazon.com/Game-Engine-Design-Interactive-Technology/dp/1558605932

    BTW, nice post again

  2. Thanks for the comment dude!

    You are the very first one to comment here 🙂

    I agree it is not a good idea to compute the ragdoll’s part during code execution, I wasn’t aware it was that expensive. Before doing this post I was researching some ways to calculate those parts programatically and I found this tool: http://bit.ly/b3l07D

    I wasn’t able to run the application, but based on the website, I guess it is a good idea to use something like this to precalculate the bodies dimensions, then you can hook those values in your application.

    Cheers,

  3. Thank you so much for this. This is an absolutely excellent tutorial, and I have been looking for something like this for days now. The bullet demo was just too confusing for someone like me who is fairly new to physics.

    I am going to try and integrate this sample with my Ogre application and see how that goes.

  4. Thanks for share. It’s very nice post

  5. First of all very good article you provided here. I was looking for some help since I also try to do ragdoll with bullet. It works great so far (very similar with your implementation). My question is how would I programmatically build the shapes of the boxes. I see your method CreateShape but you pass the dimension of the bbox by “hand”. Is there any method to determine automatically the bone dimension? Since I’m loading the bones I should know about their size, but I still cannot get it to work.
    Any suggestion would be appreciated.

  6. Thanks for the comment. Determining the dimension of the bone depends on how you are loading your mesh, on the skinned mesh file format I created I save the bones “heads” and “tails” positions in world coordinates, so it should be easy to calculate the length. But, the bone’s dimension isn’t necessarily needed for most ragdolls setups (don’t know about the one you are implementing), some bones won’t even be taken into account, just their parents, as I said on the post. I would recommend you create a tool similar to the one I did for testing the shapes’ sizes and positions. Even if you come up with a way to automatically create the shapes from the bones dimensions, I would say it is very likely you would have to tweak them by hand later, so I wouldn’t bother coming up with such an algorithm.

    Cheers,


Leave a comment


*

Trackbacks are disabled.