Proper Ragdoll format

Started by
25 comments, last by dirtysanchez 14 years, 7 months ago
Hi Guys, i'm using Tokamak physics to play with ragdolls. Till today i always used quads and now it is time to switch to skinned model - merged with ragdoll operated from Tokamak engine. I am trying to find out any format that would help me doing that, Tokamak requires Bones / Joints to create a proper ragdoll, does any one ever used Tokamak to build Skinned Ragdoll from some model?
Xynapse | http://szczerbiec.net/
Advertisement
The way it works is you have two seperate skeletons. One for the ragdoll physics, and one for the character graphics. The character graphic skeleton is usually updated with animation data, which is just a set of joint angles at a particular time.

To apply your ragdoll to the skinned model you need to generate a set of these joint angles to emulate the animation data at the current point in time. If your ragdoll and graphics are a 1 to 1 skeleton match then this is very easy, the angles are just 1 to 1 also.

Usually the ragdoll skeleton is much lower resolution for efficiency. It *at least* will not have fingers and eyes and such but it may even have fewer spine and limb joints. This is what can complicate things. You have to basically do a form of IK to generate the intermediate joint angles to make the joints that do exist coincide.

IIRC, your game is the flying robot ragdoll one with radial blur? If so, you can ignore my 3rd point. It should be easy for you to create a ragdoll skeleton which exactly fits your graphic skelton.
bzroom - thanks for the reply.

The thing is that i am not sure if any type of model is suitable for Tokamak. As tokamak requires to have bones and joints defined.

I cannot exactly understand how is the ragdollskeleton being 'transformed' to my model having joints. I know it is easier to do that by having exactly the same amount of bones/joints in 3dmodel as in ragdoll skeleton.

If there is anything that would somehow enlighten me - i would really appreciate!
Xynapse | http://szczerbiec.net/
It seems as though you have the mindset that you should start with the ragdoll and some how derive a graphics model. Infact it's the opposite way. Your ragdoll skeleton should be derived from the artist created graphic skeleton.

Any model format which includes bones is going to be a suitable format. You'll use the relative bone locations to create your ragdoll skeleton structure to be an exact fit for your graphic one, creating rigid bodies to represent each bone. So the root graphic bone will obtain the world transform of the root rigid body, and each bone after that will obtain the orientation from the ragdoll joints connecting that bone to the parent bone.

I'm not familiar with Tokamaks ragdoll structures so unfortunately my descriptions may be confusing or misleading. If you could point me to the ragdoll structure documentation, I'll look it over when I have a chance and try to give a more accurate description. But in short any boned graphic model format is a good place to start. I noticed in one of your other threads you were intersted in using MD5. That should be perfectly fine.
bzroom,

that cleared up the chaos in my mind.
I'm running my own model format now exported from MS3d.
It is skineed and runs skel. animation within. What i'll do now, is try to merge ragdoll-skeleton to this model as you mentioned and see the results.
Of course i'll drop an update here with the results.

Thanks for letting me know,
it really makes more sense to me now.
Xynapse | http://szczerbiec.net/
Just to let you have a look at tokamak's Ragdoll creation process. Here is a complete solution.

#define PI 3.141592653589793238462643fenum EBoneType {	BT_BODY,			 	BT_HEAD,			 	BT_RIGHT_ARM,	BT_LEFT_ARM	,	BT_RIGHT_FOREARM,	BT_LEFT_FOREARM	,	BT_RIGHT_THIGH,	BT_LEFT_THIGH,	BT_RIGHT_LEG,	BT_LEFT_LEG,	BT_BACKPACK,};	//	enum EBoneType;enum EBonesJointType {	BJT_BALL,		BJT_HINGE,	};	//	enum EBonesJointType;struct SBone {	float ZRotation;	neV3 Position, Size;	neRigidBody *Body;};	//	struct SBone; struct SBonesJoint { 	EBoneType BoneA, BoneB; 	neV3 Position; 	EBonesJointType Type; 	float LowerLimit, UpperLimit; 	bool EnableLimit, EnableTwistLimit; 	float TwistLimit; 	neJoint *Joint;};	//	struct SBonesJoint;static const int BonesCount = 10;SBone Bones[] = {	{	0.0f,	{	0.0f,	0.0f,	0.0f	},	{	0.55f,	0.7f,	0.3f	}	},	//	BT_BODY	{	0.0f,	{	0.0f,	0.55f,	0.0f	},	{	0.4f,	0.35f,	0.2f	}	},	//	BT_HEAD	{	PI/2,	{	-0.45f,	0.28f,	0.0f	},	{	0.25f,	0.4f,	0.2f	}	},	//	BT_RIGHT_ARM	{	PI/2,	{	0.45f,	0.28f,	0.0f	},	{	0.25f,	0.4f,	0.2f	}	},	//	BT_LEFT_ARM	{	-PI/2,	{	-0.9f,	0.28f,	0.0f	},	{	0.24f,	0.6f,	0.24f	}	},	//	BT_RIGHT_FOREARM	{	PI/2,	{	0.9f,	0.28f,	0.0f	},	{	0.24f,	0.6f,	0.24f	}	},	//	BT_LEFT_FOREARM	{	0.0f,	{	-0.2f,	-0.6f,	0.0f	},	{	0.27f,	0.7f,	0.2f	}	},	//	BT_RIGHT_THIGH	{	0.0f,	{	0.2f,	-0.6f,	0.0f	},	{	0.27f,	0.7f,	0.2f	}	},	//	BT_LEFT_THIGH	{	0.0f,	{	-0.2f,	-1.3f,	0.0f	},	{	0.3f,	0.8f,	0.3f	}	},	//	BT_RIGHT_LEG	{	0.0f,	{	0.2f,	-1.3f,	0.0f	},	{	0.3f,	0.8f,	0.3f	}	},	//	BT_LEFT_LEG};	//	SBone Bones[] static const int JointsCount = 9;// 	     BoneA,             BoneB ,             Position,                  Type ,        LowerLimit,  UpperLimit,  EnableLimit, EnableTwistLimit,TwistLimit,neJoint *Joint;  	 SBonesJoint Joints[] = {	{	BT_HEAD,			BT_BODY,		{	0.0f,	0.35f,	0.0f	},	BJT_HINGE,	-NE_PI/4,		NE_PI/4,		true,	false,	0.0f},	{	BT_RIGHT_ARM,		BT_BODY,		{	-0.22f, 0.28f,	0.0f	},	BJT_BALL,	0.0f,			NE_PI/2.5,		true,	true,	0.1f},	{	BT_LEFT_ARM,		BT_BODY,		{	0.22f,	0.28f,	0.0f	},	BJT_BALL,	0.0f,			NE_PI/2.5,		true,	true,	0.1f},	{	BT_RIGHT_FOREARM,	BT_RIGHT_ARM,	{	-0.65f,	0.28f,	0.0f	},	BJT_HINGE,	0.0f,			NE_PI/2,		true,	false,	0.0f},	{	BT_LEFT_FOREARM,	BT_LEFT_ARM,	{	0.65f,	0.28f,	0.0f	},	BJT_HINGE,	0.0f,			NE_PI/2,		true,	false,	0.0f},	{	BT_RIGHT_THIGH,		BT_BODY,		{	-0.2f,	-0.32f,	0.0f	},	BJT_BALL,	0.0f,			NE_PI/4,		true,	true,	0.8f},	{	BT_LEFT_THIGH,		BT_BODY,		{	0.2f,	-0.32f,	0.0f	},	BJT_BALL,	0.0f,			NE_PI/4,		true,	true,	0.8f},	{	BT_RIGHT_LEG,		BT_RIGHT_THIGH,	{	-0.2f,	-0.95f, 0.0f	},	BJT_HINGE,	0,0,0,0,0},	{	BT_LEFT_LEG,		BT_LEFT_THIGH,	{	0.2f,	-0.95f, 0.0f	},	BJT_HINGE,	0,0,0,0,0}, };	//	SBonesJoint Joints[]inline void neT3ToMatrix(const neT3 _Transform, float _Matrix[16]) {	_Matrix[0]	= _Transform.rot[0][0];	_Matrix[1]	= _Transform.rot[0][1];	_Matrix[2]	= _Transform.rot[0][2];	_Matrix[3]	= 0.0f;	_Matrix[4]	= _Transform.rot[1][0];	_Matrix[5]	= _Transform.rot[1][1];	_Matrix[6]	= _Transform.rot[1][2];	_Matrix[7]	= 0.0f;	_Matrix[8]	= _Transform.rot[2][0];	_Matrix[9]	= _Transform.rot[2][1];	_Matrix[10]	= _Transform.rot[2][2];	_Matrix[11]	= 0.0f;	_Matrix[12]	= _Transform.pos[0];	_Matrix[13]	= _Transform.pos[1];	_Matrix[14]	= _Transform.pos[2];	_Matrix[15]	= 1.0f;}	//	inline void neT3ToMatrix(const neT3 _Transform, float _Matrix[16])  void CreateRagDoll(neV3 &_Position ) {	float Mass = 10;	neV3 XAxis; XAxis.Set(1.0f, 0.0f, 0.0f);	neV3 ZAxis; ZAxis.Set(0.0f, 0.0f, 1.0f);	for (int i=0; i<BonesCount; i++) {		if(i==BT_RIGHT_ARM || i == BT_LEFT_ARM)Mass=2;		if(i==BT_RIGHT_FOREARM || i == BT_LEFT_FOREARM)Mass=2;		if(i==BT_RIGHT_THIGH || i == BT_LEFT_THIGH)Mass=2;		if(i==BT_RIGHT_LEG || i == BT_LEFT_LEG)Mass=2;		if(i==BT_BODY)Mass=10;		if(i==BT_HEAD)Mass=1;		 		Bones.Body = Simulator->CreateRigidBody();		Bones.Body->CollideConnected(true);				neGeometry *Geometry = Bones.Body->AddGeometry();		Geometry->SetBoxSize(Bones.Size[0]*Scale, Bones.Size[1]*Scale, Bones.Size[2]*Scale);		Bones.Body->UpdateBoundingInfo();		neV3 InertiaTensor = neBoxInertiaTensor(Bones.Size[0]*Scale, 												Bones.Size[1]*Scale, 												Bones.Size[2]*Scale, Mass);		Bones.Body->SetInertiaTensor(InertiaTensor);		Bones.Body->SetMass(Mass);		Bones.Body->SetUserData(100+i);				neV3 Position = Bones.Position * Scale + _Position;		Bones.Body->SetPos(Position);		neQ Quaternion; Quaternion.Set(Bones.ZRotation, ZAxis);		Bones.Body->SetRotation(Quaternion);	}	//	for (int i=0; i<BonesCount; i++)	neJoint *Joint; neT3 JointFrame;	for (int i=0; i<JointsCount; i++) {		Joint = Simulator->CreateJoint(Bones[Joints.BoneA].Body, Bones[Joints.BoneB].Body);		if (Joints.Type == BJT_BALL) Joint->SetType(neJoint::NE_JOINT_BALLSOCKET);		else Joint->SetType(neJoint::NE_JOINT_HINGE);		JointFrame.SetIdentity();		JointFrame.pos = Joints.Position * Scale + _Position;		Joint->SetJointFrameWorld(JointFrame);		if (Joints.EnableLimit) {			Joint->SetLowerLimit(Joints.LowerLimit);			Joint->SetUpperLimit(Joints.UpperLimit);			Joint->EnableLimit(true);		}	//	if (Joints.EnableLimit)		if (Joints.EnableTwistLimit) {			Joint->SetLowerLimit2(Joints.TwistLimit);			Joint->EnableLimit2(true);		}	//	if (Joints.EnableTwistLimit)				Joint->Enable(true);		Joints.Joint = Joint;	}	//	for (i=0; i<JointsCount; i++)}	//	void CreateRagDoll(neV3 &_Position)


Have a look.

Xynapse | http://szczerbiec.net/
No way..
i can't get this to work..

having md5 loaded into the gl app i see total difference between tokamak ragdoll requirements and data i can get from md5mesh..

it seems tokamak uses a lot more data to create ragdoll ...

numJoints 47numMeshes 2joints {	"origin"	-1 ( 0.4811630249 -0.0000028610 0.0000000000 ) ( -0.7071067810 0.0000000000 0.0000000000 )		//	"bip01"	0 ( -9.5188369750 -0.0000028610 60.3541145324 ) ( 0.0000000000 0.0000000000 -0.0000000000 )		// origin	"pelvis"	1 ( -5.0578060150 -0.0000012252 60.3541145324 ) ( 0.4999996662 0.4999999046 0.4999996662 )		// bip01	"SPINNER"	2 ( -5.0674753189 0.0000003234 67.1245803833 ) ( 0.5610293388 0.4304026126 0.4304039001 )		// pelvis	"lthigh"	3 ( -5.0578050613 10.0008354187 60.3541221618 ) ( -0.5834061622 -0.4835883617 0.4166314601 )		// SPINNER	"lcalf"	4 ( -0.5389073371 13.5598382949 36.6310081481 ) ( -0.4712568759 -0.5934116840 0.5111591339 )		// lthigh	"lfoot"	5 ( -6.4881482124 17.3538913726 11.3716907501 ) ( -0.4687849998 -0.5041595458 0.4945433616 )		// lcalf	"ltoe0"	6 ( 1.8877953529 17.3558692932 -0.0474251937 ) ( -0.6883964061 -0.0014082899 -0.0004831372 )		// lfoot	"rthigh"	3 ( -5.0578069686 -10.0008430480 60.3541183471 ) ( -0.5023481845 -0.4163796901 0.4836173534 )		// SPINNER	"rcalf"	8 ( -0.5300383090 -13.5642156600 36.6333541870 ) ( -0.4057850360 -0.5109444141 0.5934447765 )		// rthigh	"rfoot"	9 ( -6.4698333740 -17.3586616516 11.3718748092 ) ( -0.5303904533 -0.4950637340 0.5043305397 )		// rcalf	"rtoe0"	10 ( 1.8903812408 -17.3516902923 -0.0587604522 ) ( -0.7255538940 0.0007310948 -0.0000904309 )		// rfoot	"chest"	3 ( -1.8212223052 -0.0000083983 79.2687149047 ) ( 0.5559721946 0.4369155883 0.4369168758 )		// SPINNER	"spine2"	12 ( 1.1410928964 -0.0000086274 91.4858703613 ) ( 0.5647228240 0.4255448341 0.4255461215 )		// chest	"neck"	13 ( 4.6032929420 -0.0000180431 103.5735626220 ) ( 0.6724569797 0.2186382532 0.2186391592 )		// spine2	"head"	14 ( 9.5343465805 -0.0000126771 107.1591186523 ) ( 0.5154178619 0.4840913295 0.4840930461 )		// neck	"lclavicle"	14 ( 4.6061553955 8.3088197708 103.5696334838 ) ( -0.0350226211 -0.1519666671 -0.7471330165 )		// neck	"lupperArm"	16 ( 1.4367122650 27.3352127075 100.7619400024 ) ( 0.3077651500 -0.3132365703 -0.6398134231 )		// lclavicle	"lforearm"	17 ( 1.1434220075 39.3802108764 85.2917709350 ) ( 0.3071821928 -0.3138090610 -0.6409855842 )		// lupperArm	"lhand"	18 ( 0.7824479103 51.2514343261 70.0449447631 ) ( 0.6679525375 0.2118231296 -0.6815388202 )		// lforearm	"lfinger0"	19 ( 7.9092764854 53.5329475402 64.1895828247 ) ( 0.9459392547 -0.1261154174 -0.1287528152 )		// lhand	"lfinger01"	20 ( 12.8584899902 52.6375923156 62.5402641296 ) ( 0.8883567810 -0.3486094474 -0.1894884109 )		// lfinger0	"lfinger1"	19 ( 3.8787021636 58.0599861145 59.6129150390 ) ( 0.7265145301 0.1490605449 -0.6495935916 )		// lhand	"lfinger11"	22 ( 4.3646926879 59.9493408203 55.7203826904 ) ( 0.7345753669 0.1021831035 -0.6589811325 )		// lfinger1	"lfinger12"	23 ( 4.8231744766 61.2562026977 51.8133735656 ) ( -0.7399286746 0.0504764080 0.6706750392 )		// lfinger11	"lfinger2"	19 ( -3.3590462207 57.9970283508 59.9384346008 ) ( 0.6382870674 0.1741897344 -0.7372230529 )		// lhand	"lfinger21"	25 ( -3.9294841766 59.6358146667 56.4874610900 ) ( 0.6507125377 0.1196893692 -0.7461503028 )		// lfinger2	"lfinger22"	26 ( -4.4799113273 60.6679306030 52.7956809997 ) ( -0.6616077899 -0.0052459449 0.7477327346 )		// lfinger21	"rclavicle"	14 ( 4.6061539649 -8.3088407516 103.5696334838 ) ( -0.6459535598 0.7471277236 0.1528254890 )		// neck	"rupperArm"	28 ( 1.4268237113 -27.3281612396 100.7254104614 ) ( 0.6308963298 -0.6398245811 -0.3129609823 )		// rclavicle	"rforearm"	29 ( 1.1397520303 -39.3826904296 85.2625427246 ) ( 0.6297044754 -0.6409974098 -0.3135330438 )		// rupperArm	"rhand"	30 ( 0.7848826408 -51.2633056640 70.0229034423 ) ( 0.2098594665 -0.6810718059 0.2129654645 )		// rforearm	"rfinger0"	31 ( 7.9183864593 -53.5641326904 64.1832427978 ) ( 0.2697207689 -0.1280962705 -0.1246078968 )		// rhand	"rfinger01"	32 ( 12.8733806610 -52.6817169189 62.5443420410 ) ( 0.2312743425 -0.1888655185 -0.3472106218 )		// rfinger0	"jaw"	15 ( 10.6289491653 -0.0000390880 107.5216674804 ) ( -0.6648724079 -0.2407165050 0.2407176733 )		// head	"rfinger1"	31 ( 3.8860769271 -58.0817604064 59.5988044738 ) ( 0.1663712120 -0.6490144252 0.1502279996 )		// rhand	"rfinger11"	35 ( 4.3755779266 -59.9730987548 55.7076797485 ) ( 0.1244264125 -0.6583441734 0.1033168673 )		// rfinger1	"rfinger12"	36 ( 4.8390846252 -61.2818832397 51.8019104003 ) ( -0.0130878186 -0.6698714256 -0.0494819450 )		// rfinger11	"rfinger2"	31 ( -3.3521680831 -58.0002899169 59.9088287353 ) ( 0.1358649253 -0.7366971015 0.1752205467 )		// rhand	"rfinger21"	38 ( -3.9194021224 -59.6382751464 56.4569511413 ) ( 0.0731943607 -0.7455363750 0.1206698894 )		// rfinger2	"rfinger22"	39 ( -4.4645586013 -60.6696815490 52.7641944885 ) ( -0.0569608879 -0.7469521045 0.0061010932 )		// rfinger21	"bottom_lip"	34 ( 8.4189233779 -0.0000362893 105.6040191650 ) ( -0.7061348438 -0.0370621633 0.0370631790 )		// jaw	"top_lip"	15 ( 7.2049083709 -0.0000357129 107.7356643676 ) ( -0.7058193206 0.0426523971 -0.0426515007 )		// head	"lmissile"	19 ( 0.9081200599 47.0400505065 59.2516555786 ) ( 0.0002388954 -0.0080377407 -0.0029151344 )		// lhand	"rmissile"	31 ( 0.9442643165 -47.0545234680 59.2291297912 ) ( -0.0001485671 -0.0069670495 0.0041923837 )		// rhand	"lknee"	5 ( 21.1109294891 13.5514030456 36.6243934631 ) ( 0.0000537166 -0.0001528452 0.0001918395 )		// lcalf	"rknee"	9 ( 21.1197681427 -13.5645313262 36.6361160278 ) ( 0.0000005902 0.0000638169 0.0000073403 )		// rcalf}


Md5 has joints listed,
tokamak needs Bones/Joints to create a ragdoll..

damn i'm scratching my head with this for two days now..
Xynapse | http://szczerbiec.net/
Quote:Original post by dirtysanchez
damn i'm scratching my head with this for two days now..


Thats nothin.. Just keep at it man you'll get it.

One thing that is surely missing from your model file is the size to make the collision envelope for the ragdoll rigidbodies. For my game I just came up with some algorithm and lookup table for certain bones. Such as spin bones width and length were 1/4 the height, etc. It worked out pretty well.

The way the pros do it is they use a model format which allows the artist to explicitly define the shape of each ragdoll bone. So if you can find a model format which allows you to tag your geometry you could create geometry for all the bones and tag it as follows:

tags:
ragdoll_bone_spine1_collison

Or something. That way in code you'll know how big to make the bone. You'll also need to come up with some way to specify joint axis limits. I used a lookup table for that. So my model was accompanied with an xml file which defined all these parameters for each bone define in the graphic model file.
Sure thing mate,
i'm on it...

But it is really a headache...

I would love to hear it is possible to be done with Tokamak - based on what i wrote up there(before) - this would kick my ass to progress with this..

Gotta make it!
Xynapse | http://szczerbiec.net/
Ok, i made another step forward.

My mesh is rendered perfectly also
i'm able to get the joints rendered /set up 'almost' properly.
A small pic:



going forward...
Xynapse | http://szczerbiec.net/

This topic is closed to new replies.

Advertisement