6Dof constraints rubber-band all over the place

User avatar
Dragonlord
Posts: 198
Joined: Mon Sep 04, 2006 5:31 pm
Location: Switzerland

6Dof constraints rubber-band all over the place

Post by Dragonlord »

This problem annoys the hell out of me since month now but it had not been yet high up enough on the task list.

Simple problem. Have a rag-doll with 6-Dof constraints. Let's say a typical human body. Grabbing the head and moving it around feels like if the neck is made out of a rubber band as it stretches up to 3 times the length. This is really a nuisance as I know of no skeleton where bones stretch to 3 times their length.

I tried messing with the constraint parameters:

Code: Select all

	int l;
	
	for( l=0; l<3; l++ ){ // linear limits
		generic6Dof->setParam( BT_CONSTRAINT_CFM, 0.0f, l ); // default 0.0f
		generic6Dof->setParam( BT_CONSTRAINT_STOP_CFM, 0.0f, l ); // default 0.0f
		generic6Dof->setParam( BT_CONSTRAINT_STOP_ERP, 0.2f, l ); // default 0.2f
	}
	btTranslationalLimitMotor &motorLinear = *generic6Dof->getTranslationalLimitMotor();
	motorLinear.m_damping = 1.0f; // Damping for linear limit: default 1.0
	motorLinear.m_limitSoftness = 0.7f; // Softness for linear limit: default 0.7
	motorLinear.m_restitution = 0.5f; // Bounce parameter for linear limit: default 0.5
	
	for( l=0; l<3; l++ ){ // angular limits
		generic6Dof->setParam( BT_CONSTRAINT_CFM, 0.0f, 3 + l ); // Constraint force mixing factor: default 0.0
		generic6Dof->setParam( BT_CONSTRAINT_STOP_ERP, 0.2f, 3 + l ); // Error tolerance factor when joint is at limit: default 0.2
		generic6Dof->setParam( BT_CONSTRAINT_STOP_CFM, 0.0f, 3 + l ); // Constraint force mixing factor when joint is at limit: default 0.0
		btRotationalLimitMotor &motorAngular = *generic6Dof->getRotationalLimitMotor( l );
		motorAngular.m_damping = 1.0f; // Damping: default 1.0
		motorAngular.m_limitSoftness = 0.5f; // Relaxation factor: default 0.5
		motorAngular.m_bounce = 0.0f; // restitution factor: default 0.0
	}
But no matter what kind of values I use, even totally crazy ones like 1000.0, have exactly no effect at all. Looking further I noticed (using printf) that the solveAngularLimits respective solveLinearAxis of btRotationalLimitMotor respective btTranslationalLimitMotor are implemented but never used.

How can I disable this rubber-band effect?
If not where is the solving implemented (actually not in solve* in *LimitMotor as one expects) so I can hack it over to not be rubber-banding?
Kanttori
Posts: 38
Joined: Thu Jul 08, 2010 12:52 am

Re: 6Dof constraints rubber-band all over the place

Post by Kanttori »

Iirc I had a somewhat similar issue with blender and the .bullet-file, the constraint actually used in blender (don't remember when it changed, 2.5 something?) was btGeneric6DofSpringConstraint and not btGeneric6DofConstraint, there was a noticeable difference in rigidity. Any chance of being a similar issue?

Anyway, as the manual says you should at least try to use conetwist for ragdolls.
User avatar
Dragonlord
Posts: 198
Joined: Mon Sep 04, 2006 5:31 pm
Location: Switzerland

Re: 6Dof constraints rubber-band all over the place

Post by Dragonlord »

I'm using the non-spring version so that's not the problem there. Concerning ConeTwist I'm not using it as it is FUBAR. Even with a simple rig of 3 bones it explodes in a couple of seconds littering all bones all over the place. 6Dof with the same limits is stable but as mentioned a rubber-band hell. So right now I have the choice between explosion (totally unusable) and rubber-banding (usable but very annoying).
ouch67
Posts: 17
Joined: Tue Jul 26, 2011 9:24 pm

Re: 6Dof constraints rubber-band all over the place

Post by ouch67 »

the ragdoll demo uses cones, but it also uses only 1kg for each limb, try adjusting your weights, bullet seems to be a bit sensitive to differing weights.
User avatar
Dragonlord
Posts: 198
Joined: Mon Sep 04, 2006 5:31 pm
Location: Switzerland

Re: 6Dof constraints rubber-band all over the place

Post by Dragonlord »

Weight has no influence. My limbs are not heavier than 1 or 2 kg and I tried various weight ranges. ConeTwist just explodes no matter what. 6Dof is stable enough except this problem there.
Kanttori
Posts: 38
Joined: Thu Jul 08, 2010 12:52 am

Re: 6Dof constraints rubber-band all over the place

Post by Kanttori »

The fubar conetwist seem pretty good when tested on blender, the params are not directly the same as with 6dof though explosions should not occur I think. Could you post some code you're using to setup things, since atm. it's hard to get a grip on this issue. Personally I'd just make sure the btTransforms used with constraints etc. don't have scale and are set to identity at start if you're not manually setting both the rotation and the translation.
User avatar
Dragonlord
Posts: 198
Joined: Mon Sep 04, 2006 5:31 pm
Location: Switzerland

Re: 6Dof constraints rubber-band all over the place

Post by Dragonlord »

Code: Select all

	decQuaternion orientation2 = pConstraint->GetOrientation2();
	decVector position1 = pConstraint->GetPosition1() - pOffset1;
	decVector position2 = pConstraint->GetPosition2() - pOffset2;
	decVector lowerLimits = pConstraint->GetAngularLowerLimits();
	decVector upperLimits = pConstraint->GetAngularUpperLimits();
	decVector linearOffset = pConstraint->GetLinearLowerLimits();
	decVector center, swing, aswing, lower, upper;
	btConeTwistConstraint *coneTwist = NULL;
	decMatrix matrix, axisMatrix;
	decQuaternion orientation;
	
	// NOTES:
	// setLimit( span1, span2, twist )
	// span1 = Z-Axis
	// span2 = Y-Axis
	// twist = X-Axis ( in demo set to 0 all times )
	// span is always the entire range not just half the range
	
	// alter the positions using the locked linear axes
	matrix.SetFromQuaternion( orientation1 );
	position1 += matrix * linearOffset;
	
	// determine the swing spans of all angular degrees of freedom. to prevent
	// potential numerical problems the swing spans are clamped to zero.
	swing = ( upperLimits - lowerLimits );
	if( swing.x < 0.0f ) swing.x = 0.0f;
	if( swing.y < 0.0f ) swing.y = 0.0f;
	if( swing.z < 0.0f ) swing.z = 0.0f;
	center = ( upperLimits + lowerLimits ) * 0.5f;
	
	// use the axis with the smallest swing span as the twist axis
	// which is the x axis in bullet. if more than one swing span
	// is the smallest x wins over y and y over z.
	if( swing.x <= swing.y && swing.x <= swing.z ){ // x span is smallest
		//axisMatrix.SetIdentity(); // default by construction
		aswing = swing;
		
	}else if( swing.y <= swing.x && swing.y <= swing.z ){ // y span is smallest
		axisMatrix.a11 = 0.0f; axisMatrix.a12 = 1.0f; axisMatrix.a13 = 0.0f;
		axisMatrix.a21 = -1.0f; axisMatrix.a22 = 0.0f; axisMatrix.a23 = 0.0f;
		axisMatrix.a31 = 0.0f; axisMatrix.a32 = 0.0f; axisMatrix.a33 = 1.0f;
		aswing.Set( swing.y, swing.x, swing.z );
		
	}else{ // z span is smallest
		axisMatrix.a11 = 0.0f; axisMatrix.a12 = 0.0f; axisMatrix.a13 = 1.0f;
		axisMatrix.a21 = 0.0f; axisMatrix.a22 = 1.0f; axisMatrix.a23 = 0.0f;
		axisMatrix.a31 = -1.0f; axisMatrix.a32 = 0.0f; axisMatrix.a33 = 0.0f;
		aswing.Set( swing.z, swing.y, swing.x );
	}
	
	// determines the orientation of the bodies. the orientation takes into account
	// the center correction and axis realignment
	orientation1 = ( axisMatrix * decMatrix::CreateFromQuaternion( orientation1 ) ).ToQuaternion();
	orientation2 = ( decMatrix::CreateRotation( center ) * axisMatrix * decMatrix::CreateFromQuaternion( orientation2 ) ).ToQuaternion();
	
	// create a constraint for two bodies if phy body 2 is not NULL
	if( pPhyBody2 ){
		coneTwist = new btConeTwistConstraint( *pPhyBody1->GetRigidBody(), *pPhyBody2->GetRigidBody(),
			btTransform(
				btQuaternion( orientation1.x, orientation1.y, orientation1.z, orientation1.w ),
				btVector3( position1.x, position1.y, position1.z ) ),
			btTransform(
				btQuaternion( orientation2.x, orientation2.y, orientation2.z, orientation2.w ),
				btVector3( position2.x, position2.y, position2.z ) ) );
		
	// otherwise create a single body constraint
	}else{
		coneTwist = new btConeTwistConstraint( *pPhyBody1->GetRigidBody(),
			btTransform(
				btQuaternion( orientation1.x, orientation1.y, orientation1.z, orientation1.w ),
				btVector3( position1.x, position1.y, position1.z ) ),
			btTransform(
				btQuaternion( orientation2.x, orientation2.y, orientation2.z, orientation2.w ),
				btVector3( position2.x, position2.y, position2.z ) ) );
	}
	pBpConstraint = coneTwist;
	
	// set the limits using the realligned swing spans
	coneTwist->setLimit( aswing.x, aswing.y, aswing.z, 1.0f, 0.3f, 1.0f );
With a straight rope type rig with very large swings it doesn't explode but the rubber-banding is happening there the same as with 6Dof so that's a generic problem. Hence the linear constraint (no movement!) is violated up to 0.5m with the individual bone spazzing around like on drugs. Funny thing is that the hinge constraint can keep the linear constraint valid with next to no error visible while ConeTwist and especially 6Dof totally fail at it.
cyprien
Posts: 3
Joined: Sun Jul 24, 2011 11:34 pm

Re: 6Dof constraints rubber-band all over the place

Post by cyprien »

Hello,

Did you try to adjust the number of iteration of the constraint solver ?

btContactSolverInfo& info = world->getSolverInfo();
info.m_numIterations = 20; // 5-20 (if i did correctly understood this param)

Or if you can, you could try to reduce the timestep of the simulation, that would allow more physical steps and make constraint less "soft".
That did help us with stability and rigidity of contraints in our project.

Cyorueb
User avatar
Dragonlord
Posts: 198
Joined: Mon Sep 04, 2006 5:31 pm
Location: Switzerland

Re: 6Dof constraints rubber-band all over the place

Post by Dragonlord »

I've seen that parameter already but I've no idea what exactly it does or what the range of values is. Any pointers?

Concerning the simulation time step what are you using? I'm using right now the default of Bullet hence 60Hz. with unlimited sub-steps (actually 400 but that would be rouhgly 8 seconds lag which is highly unlikely).
Kanttori
Posts: 38
Joined: Thu Jul 08, 2010 12:52 am

Re: 6Dof constraints rubber-band all over the place

Post by Kanttori »

Does the x-axis of the localspace frames to conetwist align with the direction of your ropesegments? I think there may sometimes also be an issue with gimbal lock so the constraint starts working against itself on different axises, at least the parameters to conetwist allow such a situation.

Do you disable collision between the bones when adding the constraint? These are simple questions, unfortunately can't do better; don't know the mathapi and would be too involved to start analyzing that code, you should just do printout's of the values going to constraints and see if you're satisfied with them.
User avatar
Dragonlord
Posts: 198
Joined: Mon Sep 04, 2006 5:31 pm
Location: Switzerland

Re: 6Dof constraints rubber-band all over the place

Post by Dragonlord »

Kanttori wrote:Does the x-axis of the localspace frames to conetwist align with the direction of your ropesegments? I think there may sometimes also be an issue with gimbal lock so the constraint starts working against itself on different axises, at least the parameters to conetwist allow such a situation.

Code: Select all

   // use the axis with the smallest swing span as the twist axis
   // which is the x axis in bullet. if more than one swing span
   // is the smallest x wins over y and y over z.
Do you disable collision between the bones when adding the constraint? These are simple questions, unfortunately can't do better; don't know the mathapi and would be too involved to start analyzing that code, you should just do printout's of the values going to constraints and see if you're satisfied with them.
No bone collisions between bones and their parents. Concerning the values as mentioned above they are find. The problem is not the values but the constraint exploding for no reason. ConeTwist had though been a problem child since the early implementation (exploded already there). Rubber-banding is also a never problem which showed up I think around 2.75 or something like that (not sure about the exact version). Before I did not have rubber-banding with the same configuration.
Kanttori
Posts: 38
Joined: Thu Jul 08, 2010 12:52 am

Re: 6Dof constraints rubber-band all over the place

Post by Kanttori »

Well, if you say everything is fine then it must be.
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA

Re: 6Dof constraints rubber-band all over the place

Post by Erwin Coumans »

The iterative constraint solver is not perfect, but there are things to improve the convergence to a better solution:
Grabbing the head and moving it around feels
How are you exactly grabbing the head? It helps if this grabbing constraint is much weaker than the ragdoll constraints. Don't directly set the position or velocity to grab objects.

If you are using a point to point constraint for grabbing, just like in the Bullet demos, it is a good idea to limit the maximum force/impulse used (see also Bullet/Demos/OpenGL/DemoApplication/mouseFunc)

Code: Select all

		btPoint2PointConstraint* p2p = new btPoint2PointConstraint(*body,localPivot);
		m_dynamicsWorld->addConstraint(p2p);
		m_pickConstraint = p2p;
		p2p->m_setting.m_impulseClamp = mousePickClamping;//tweak this value
Secondly, increasing the number of solver iterations should help.

Code: Select all

btContactSolverInfo& info = world->getSolverInfo();
info.m_numIterations = 20; //more iterations will allow the solver to converge to the actual solution better
Decreasing the internal timestep should help too.

Code: Select all

world->stepSimulation(deltaTime, 10, 1.f/240.0f);
Another thing that improves the behaviour is to make sure that the point to point (grabbing constraint) is solved before the ragdoll constraints. I don't know out of the top of my head how to achieve this, but you could try adding the constraint before the ragdoll (as inactive constraint) and activate it later. You can enable/disable constraints using:

Code: Select all

constraint->setEnabled(true/false);
Thanks,
Erwin
User avatar
Dragonlord
Posts: 198
Joined: Mon Sep 04, 2006 5:31 pm
Location: Switzerland

Re: 6Dof constraints rubber-band all over the place

Post by Dragonlord »

The effect happens not only when I move the head using a Point2Point constraint. Happens also just while having an object dangling from the ceiling like for example a sack hung up on a flexible tube for example. Some screenshots I made. First is the head scenario just holding it after it became balanced (little force except gravity). Red lines are the joint error hence how much the bone is off compared to the rest position (bones are not allowed to stretch or move linearly). The second and third image is the hanging object scenario with a good case and a worse case. Even in good case it is not acceptable. image1, image2, image3.

I'll try though the proposed changes. Let's see if something sticks.

EDIT: So you can sort of "sort" constraints? I guess it would help if limbo constraints (aka constraints with only one rigid body and other end is the static world so to speak) are solved before regular constraints. How though is the order of the constraints affecting the solving? Right now my code just creates the constraints the first time an object is processed if not created already. This way the order of constraints I don't know and can thus be arbitrary (except inside objects constraints come before their parent constraints).