Rotatable ragdoll?

Paril
Posts: 18
Joined: Tue Feb 22, 2011 4:14 am

Rotatable ragdoll?

Post by Paril »

I'm trying to figure out how I can modify the ragdoll example (the one with 6dof constraints) so that you can pass an orientation to it and it will spawn at that orientation - has anyone tried this yet (and succeeded)?

I tried something like:

Code: Select all

		btTransform rot; rot.setIdentity();
		rot.setRotation(btQuaternion(0, 0, 0)); // (except 0 0 0 would be some angle)
then just multiplying offsets, local anchors and lower/upper angle. I think my lower/upper angle part is what is failing; the ragdoll spawns at the proper angle but then proceeds to turn into a crab and explode all over the place..

Code: Select all

			joint6DOF->setAngularLowerLimit(rot * btVector3(-SIMD_PI*0.3f,-SIMD_EPSILON,-SIMD_PI*0.3f));
			joint6DOF->setAngularUpperLimit(rot * btVector3(SIMD_PI*0.5f,SIMD_EPSILON,SIMD_PI*0.3f));
This is, for example, the spine/head constraint.

Anyone know how I may work this?

-P
Kanttori
Posts: 38
Joined: Thu Jul 08, 2010 12:52 am

Re: Rotatable ragdoll?

Post by Kanttori »

If the code works at 0,0,0 with no rotation I think all you need to do is to transform the rigidbodies to their new places. What I mean is that you may be trying to adjust things defined in per rigidbody localspace which don't need to be altered.
Paril
Posts: 18
Joined: Tue Feb 22, 2011 4:14 am

Re: Rotatable ragdoll?

Post by Paril »

I tried that though, the angles seem to be in world space; if I rotate the body around yaw 180 degrees, the arms and legs bend backwards.

Keep in mind I'm also trying to move the constraints themselves, because afaik moving the rigid bodies won't move the constraint points.. although I could be wrong on that end and that may be where I'm failing...

EDIT: Okay, I think I see what you mean. I should spawn the ragdoll at 0,0,0 with default rotation, set up constraints, and AFTERWARDS apply the rotation to the rigid bodies. I'll try that!

-P
Paril
Posts: 18
Joined: Tue Feb 22, 2011 4:14 am

Re: Rotatable ragdoll?

Post by Paril »

Kanttori, I tried applying a rotation to the transform of each part when they spawn, but the body just like violently rotates to try to get back to its basis position.

I'm really not sure what to do at this point.

Code: Select all

	RagDoll (btDynamicsWorld* ownerWorld, const btVector3& positionOffset, vec3_t angles, float scale_ragdoll)
		: m_ownerWorld (ownerWorld)
	{
		// Setup the geometry
		m_shapes[BODYPART_PELVIS] = new btCapsuleShape(scale_ragdoll*btScalar(0.15), scale_ragdoll*btScalar(0.20));
		m_shapes[BODYPART_SPINE] = new btCapsuleShape(scale_ragdoll*btScalar(0.15), scale_ragdoll*btScalar(0.28));
		m_shapes[BODYPART_HEAD] = new btCapsuleShape(scale_ragdoll*btScalar(0.10), scale_ragdoll*btScalar(0.05));
		m_shapes[BODYPART_LEFT_UPPER_LEG] = new btCapsuleShape(scale_ragdoll*btScalar(0.07), scale_ragdoll*btScalar(0.45));
		m_shapes[BODYPART_LEFT_LOWER_LEG] = new btCapsuleShape(scale_ragdoll*btScalar(0.05), scale_ragdoll*btScalar(0.37));
		m_shapes[BODYPART_RIGHT_UPPER_LEG] = new btCapsuleShape(scale_ragdoll*btScalar(0.07), scale_ragdoll*btScalar(0.45));
		m_shapes[BODYPART_RIGHT_LOWER_LEG] = new btCapsuleShape(scale_ragdoll*btScalar(0.05), scale_ragdoll*btScalar(0.37));
		m_shapes[BODYPART_LEFT_UPPER_ARM] = new btCapsuleShape(scale_ragdoll*btScalar(0.05), scale_ragdoll*btScalar(0.33));
		m_shapes[BODYPART_LEFT_LOWER_ARM] = new btCapsuleShape(scale_ragdoll*btScalar(0.04), scale_ragdoll*btScalar(0.25));
		m_shapes[BODYPART_RIGHT_UPPER_ARM] = new btCapsuleShape(scale_ragdoll*btScalar(0.05), scale_ragdoll*btScalar(0.33));
		m_shapes[BODYPART_RIGHT_LOWER_ARM] = new btCapsuleShape(scale_ragdoll*btScalar(0.04), scale_ragdoll*btScalar(0.25));

		// Setup all the rigid bodies
		btTransform offset; offset.setIdentity();
		offset.setOrigin(positionOffset);

		btTransform transform;
		transform.setIdentity();
		transform.setOrigin(btVector3(scale_ragdoll*btScalar(0.), scale_ragdoll*btScalar(1.), scale_ragdoll*btScalar(0.)));
		m_bodies[BODYPART_PELVIS] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_PELVIS], "models/physics/ragdoll/pelvis.md2");

		transform.setIdentity();
		transform.setOrigin(btVector3(scale_ragdoll*btScalar(0.), scale_ragdoll*btScalar(1.2), scale_ragdoll*btScalar(0.)));
		m_bodies[BODYPART_SPINE] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_SPINE], "models/physics/ragdoll/chest.md2");

		transform.setIdentity();
		transform.setOrigin(btVector3(scale_ragdoll*btScalar(0.), scale_ragdoll*btScalar(1.6), scale_ragdoll*btScalar(0.)));
		m_bodies[BODYPART_HEAD] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_HEAD], "models/physics/ragdoll/head.md2");

		transform.setIdentity();
		transform.setOrigin(btVector3(scale_ragdoll*btScalar(-0.18), scale_ragdoll*btScalar(0.65), scale_ragdoll*btScalar(0.)));
		m_bodies[BODYPART_LEFT_UPPER_LEG] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_LEFT_UPPER_LEG], "models/physics/ragdoll/upperleg.md2");

		transform.setIdentity();
		transform.setOrigin(btVector3(scale_ragdoll*btScalar(-0.18), scale_ragdoll*btScalar(0.2), scale_ragdoll*btScalar(0.)));
		m_bodies[BODYPART_LEFT_LOWER_LEG] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_LEFT_LOWER_LEG], "models/physics/ragdoll/lowerleg.md2");

		transform.setIdentity();
		transform.setOrigin(btVector3(scale_ragdoll*btScalar(0.18),scale_ragdoll* btScalar(0.65), scale_ragdoll*btScalar(0.)));
		m_bodies[BODYPART_RIGHT_UPPER_LEG] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_RIGHT_UPPER_LEG], "models/physics/ragdoll/upperleg.md2");

		transform.setIdentity();
		transform.setOrigin(btVector3(scale_ragdoll*btScalar(0.18), scale_ragdoll*btScalar(0.2), scale_ragdoll*btScalar(0.)));
		m_bodies[BODYPART_RIGHT_LOWER_LEG] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_RIGHT_LOWER_LEG], "models/physics/ragdoll/lowerleg.md2");

		transform.setIdentity();
		transform.setOrigin(btVector3(scale_ragdoll*btScalar(-0.35), scale_ragdoll*btScalar(1.45), scale_ragdoll*btScalar(0.)));
		transform.getBasis().setEulerZYX(0,0,M_PI_2);
		m_bodies[BODYPART_LEFT_UPPER_ARM] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_LEFT_UPPER_ARM], "models/physics/ragdoll/lupperarm.md2");

		transform.setIdentity();
		transform.setOrigin(btVector3(scale_ragdoll*btScalar(-0.7), scale_ragdoll*btScalar(1.45), scale_ragdoll*btScalar(0.)));
		transform.getBasis().setEulerZYX(0,0,M_PI_2);
		m_bodies[BODYPART_LEFT_LOWER_ARM] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_LEFT_LOWER_ARM], "models/physics/ragdoll/llowerarm.md2");

		transform.setIdentity();
		transform.setOrigin(btVector3(scale_ragdoll*btScalar(0.35), scale_ragdoll*btScalar(1.45), scale_ragdoll*btScalar(0.)));
		transform.getBasis().setEulerZYX(0,0,-M_PI_2);
		m_bodies[BODYPART_RIGHT_UPPER_ARM] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_RIGHT_UPPER_ARM], "models/physics/ragdoll/rupperarm.md2");

		transform.setIdentity();
		transform.setOrigin(btVector3(scale_ragdoll*btScalar(0.7), scale_ragdoll*btScalar(1.45), scale_ragdoll*btScalar(0.)));
		transform.getBasis().setEulerZYX(0,0,-M_PI_2);
		m_bodies[BODYPART_RIGHT_LOWER_ARM] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_RIGHT_LOWER_ARM], "models/physics/ragdoll/rlowerarm.md2");

		transform.setIdentity();
		transform.setRotation(EulerToQuat(angles));

		// Setup some damping on the m_bodies
		for (int i = 0; i < BODYPART_COUNT; ++i)
		{
			m_bodies[i]->setDamping(0.05, 0.85);
			m_bodies[i]->setDeactivationTime(0.8);
			m_bodies[i]->setSleepingThresholds(1.6, 2.5);

			var trans = m_bodies[i]->getWorldTransform();
			trans *= transform;
			m_bodies[i]->setWorldTransform(trans);
	}

		// Now setup the constraints
		btHingeConstraint* hingeC;
		btConeTwistConstraint* coneC;

		btTransform localA, localB;

		localA.setIdentity(); localB.setIdentity();
		localA.getBasis().setEulerZYX(0,M_PI_2,0); localA.setOrigin(btVector3(scale_ragdoll*btScalar(0.), scale_ragdoll*btScalar(0.15), scale_ragdoll*btScalar(0.)));
		localB.getBasis().setEulerZYX(0,M_PI_2,0); localB.setOrigin(btVector3(scale_ragdoll*btScalar(0.), scale_ragdoll*btScalar(-0.15), scale_ragdoll*btScalar(0.)));
		hingeC =  new btHingeConstraint(*m_bodies[BODYPART_PELVIS], *m_bodies[BODYPART_SPINE], localA, localB);
		hingeC->setLimit(btScalar(-M_PI_4), btScalar(M_PI_2));
		m_joints[JOINT_PELVIS_SPINE] = hingeC;
		hingeC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE);

		m_ownerWorld->addConstraint(m_joints[JOINT_PELVIS_SPINE], true);


		localA.setIdentity(); localB.setIdentity();
		localA.getBasis().setEulerZYX(0,0,M_PI_2); localA.setOrigin(scale_ragdoll*btVector3(btScalar(0.), btScalar(0.30), btScalar(0.)));
		localB.getBasis().setEulerZYX(0,0,M_PI_2); localB.setOrigin(scale_ragdoll*btVector3(btScalar(0.), btScalar(-0.14), btScalar(0.)));
		coneC = new btConeTwistConstraint(*m_bodies[BODYPART_SPINE], *m_bodies[BODYPART_HEAD], localA, localB);
		coneC->setLimit(M_PI_4, M_PI_4, M_PI_2);
		m_joints[JOINT_SPINE_HEAD] = coneC;
		coneC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE);

		m_ownerWorld->addConstraint(m_joints[JOINT_SPINE_HEAD], true);


		localA.setIdentity(); localB.setIdentity();
		localA.getBasis().setEulerZYX(0,0,-M_PI_4*5); localA.setOrigin(scale_ragdoll*btVector3(btScalar(-0.18), btScalar(-0.10), btScalar(0.)));
		localB.getBasis().setEulerZYX(0,0,-M_PI_4*5); localB.setOrigin(scale_ragdoll*btVector3(btScalar(0.), btScalar(0.225), btScalar(0.)));
		coneC = new btConeTwistConstraint(*m_bodies[BODYPART_PELVIS], *m_bodies[BODYPART_LEFT_UPPER_LEG], localA, localB);
		coneC->setLimit(M_PI_4, M_PI_4, 0);
		m_joints[JOINT_LEFT_HIP] = coneC;
		coneC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE);

		m_ownerWorld->addConstraint(m_joints[JOINT_LEFT_HIP], true);

		localA.setIdentity(); localB.setIdentity();
		localA.getBasis().setEulerZYX(0,M_PI_2,0); localA.setOrigin(scale_ragdoll*btVector3(btScalar(0.), btScalar(-0.225), btScalar(0.)));
		localB.getBasis().setEulerZYX(0,M_PI_2,0); localB.setOrigin(scale_ragdoll*btVector3(btScalar(0.), btScalar(0.185), btScalar(0.)));
		hingeC =  new btHingeConstraint(*m_bodies[BODYPART_LEFT_UPPER_LEG], *m_bodies[BODYPART_LEFT_LOWER_LEG], localA, localB);
		hingeC->setLimit(btScalar(0), btScalar(M_PI_2));
		m_joints[JOINT_LEFT_KNEE] = hingeC;
		hingeC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE);

		m_ownerWorld->addConstraint(m_joints[JOINT_LEFT_KNEE], true);


		localA.setIdentity(); localB.setIdentity();
		localA.getBasis().setEulerZYX(0,0,M_PI_4); localA.setOrigin(scale_ragdoll*btVector3(btScalar(0.18), btScalar(-0.10), btScalar(0.)));
		localB.getBasis().setEulerZYX(0,0,M_PI_4); localB.setOrigin(scale_ragdoll*btVector3(btScalar(0.), btScalar(0.225), btScalar(0.)));
		coneC = new btConeTwistConstraint(*m_bodies[BODYPART_PELVIS], *m_bodies[BODYPART_RIGHT_UPPER_LEG], localA, localB);
		coneC->setLimit(M_PI_4, M_PI_4, 0);
		m_joints[JOINT_RIGHT_HIP] = coneC;
		coneC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE);

		m_ownerWorld->addConstraint(m_joints[JOINT_RIGHT_HIP], true);

		localA.setIdentity(); localB.setIdentity();
		localA.getBasis().setEulerZYX(0,M_PI_2,0); localA.setOrigin(scale_ragdoll*btVector3(btScalar(0.), btScalar(-0.225), btScalar(0.)));
		localB.getBasis().setEulerZYX(0,M_PI_2,0); localB.setOrigin(scale_ragdoll*btVector3(btScalar(0.), btScalar(0.185), btScalar(0.)));
		hingeC =  new btHingeConstraint(*m_bodies[BODYPART_RIGHT_UPPER_LEG], *m_bodies[BODYPART_RIGHT_LOWER_LEG], localA, localB);
		hingeC->setLimit(btScalar(0), btScalar(M_PI_2));
		m_joints[JOINT_RIGHT_KNEE] = hingeC;
		hingeC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE);

		m_ownerWorld->addConstraint(m_joints[JOINT_RIGHT_KNEE], true);


		localA.setIdentity(); localB.setIdentity();
		localA.getBasis().setEulerZYX(0,0,M_PI); localA.setOrigin(scale_ragdoll*btVector3(btScalar(-0.2), btScalar(0.15), btScalar(0.)));
		localB.getBasis().setEulerZYX(0,0,M_PI_2); localB.setOrigin(scale_ragdoll*btVector3(btScalar(0.), btScalar(-0.18), btScalar(0.)));
		coneC = new btConeTwistConstraint(*m_bodies[BODYPART_SPINE], *m_bodies[BODYPART_LEFT_UPPER_ARM], localA, localB);
		coneC->setLimit(M_PI_2, M_PI_2, 0);
		coneC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE);

		m_joints[JOINT_LEFT_SHOULDER] = coneC;
		m_ownerWorld->addConstraint(m_joints[JOINT_LEFT_SHOULDER], true);

		localA.setIdentity(); localB.setIdentity();
		localA.getBasis().setEulerZYX(0,M_PI_2,0); localA.setOrigin(scale_ragdoll*btVector3(btScalar(0.), btScalar(0.18), btScalar(0.)));
		localB.getBasis().setEulerZYX(0,M_PI_2,0); localB.setOrigin(scale_ragdoll*btVector3(btScalar(0.), btScalar(-0.14), btScalar(0.)));
		hingeC =  new btHingeConstraint(*m_bodies[BODYPART_LEFT_UPPER_ARM], *m_bodies[BODYPART_LEFT_LOWER_ARM], localA, localB);
		//		hingeC->setLimit(btScalar(-M_PI_2), btScalar(0));
		hingeC->setLimit(btScalar(0), btScalar(M_PI_2));
		m_joints[JOINT_LEFT_ELBOW] = hingeC;
		hingeC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE);

		m_ownerWorld->addConstraint(m_joints[JOINT_LEFT_ELBOW], true);



		localA.setIdentity(); localB.setIdentity();
		localA.getBasis().setEulerZYX(0,0,0); localA.setOrigin(scale_ragdoll*btVector3(btScalar(0.2), btScalar(0.15), btScalar(0.)));
		localB.getBasis().setEulerZYX(0,0,M_PI_2); localB.setOrigin(scale_ragdoll*btVector3(btScalar(0.), btScalar(-0.18), btScalar(0.)));
		coneC = new btConeTwistConstraint(*m_bodies[BODYPART_SPINE], *m_bodies[BODYPART_RIGHT_UPPER_ARM], localA, localB);
		coneC->setLimit(M_PI_2, M_PI_2, 0);
		m_joints[JOINT_RIGHT_SHOULDER] = coneC;
		coneC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE);

		m_ownerWorld->addConstraint(m_joints[JOINT_RIGHT_SHOULDER], true);

		localA.setIdentity(); localB.setIdentity();
		localA.getBasis().setEulerZYX(0,M_PI_2,0); localA.setOrigin(scale_ragdoll*btVector3(btScalar(0.), btScalar(0.18), btScalar(0.)));
		localB.getBasis().setEulerZYX(0,M_PI_2,0); localB.setOrigin(scale_ragdoll*btVector3(btScalar(0.), btScalar(-0.14), btScalar(0.)));
		hingeC =  new btHingeConstraint(*m_bodies[BODYPART_RIGHT_UPPER_ARM], *m_bodies[BODYPART_RIGHT_LOWER_ARM], localA, localB);
		//		hingeC->setLimit(btScalar(-M_PI_2), btScalar(0));
		hingeC->setLimit(btScalar(0), btScalar(M_PI_2));
		m_joints[JOINT_RIGHT_ELBOW] = hingeC;
		hingeC->setDbgDrawSize(CONSTRAINT_DEBUG_SIZE);

		m_ownerWorld->addConstraint(m_joints[JOINT_RIGHT_ELBOW], true);
	}
Is there something I'm missing? Do I have to also rotate the local points of the joints?

-P
Kanttori
Posts: 38
Joined: Thu Jul 08, 2010 12:52 am

Re: Rotatable ragdoll?

Post by Kanttori »

In your earlier post you're multiplying the 6DOF limit setting btVector by a btTransform? That's not good... as in no good at all since those are _angular_ limits.

Hmm.. if I read that correctly you should remove the rotation setting you've added(?) in the "//Setup some damping"-loop and just add it to the original "//Setup all the rigid bodies".

Code: Select all

// Setup all the rigid bodies
btTransform offset; offset.setIdentity();
offset.setOrigin(positionOffset);
offset.setRotation(EulerToQuat(angles));
AFAIK; when you define stuff around the origo all you need to do is to multiply it with the transform the rigidbodies to get it to another place. Constraint "frames" (localA/B) are defined in per rigidbody localspace so you can move rigidbodies around as much as you like and constraints will still have the same limits so don't touch them.
Paril
Posts: 18
Joined: Tue Feb 22, 2011 4:14 am

Re: Rotatable ragdoll?

Post by Paril »

Yeah, I eventually figured it out and got my ragdoll angled.

Thanks for the insight!

-P