Transforms for creating a btConeTwistConstraint

Digitalghost
Posts: 25
Joined: Thu Dec 20, 2007 4:03 am

Transforms for creating a btConeTwistConstraint

Post by Digitalghost »

Hey all,

I'm trying to implement a ragdoll physics engine. I don't understand how the constraint is interpreting the transforms that go into it on creation. I mean, what should the transforms do to the rigid bodies. Should they rotate them so their z-axis point towards each other and are co-linear? If I have a box for a chest with x,y,z being right, up, and backwards, respectively, and another box for an arm with the same rotation, how should I create a cone-twist constraint so that the "twist" will actually twist the arm? I think i'm messing up the transforms and the twist is rotating the arm or something weird to that effect.

I tried to look for documentation on cone twist constraints but I couldn't find any. Does anyone know of a place where I can see a definition or something?

I made a render of the model to help illustrate what I'm trying to do:

Image

I have created boxes for the chest and arm and I would like to make a cone twist constraint between them.
vagr
Posts: 13
Joined: Tue Mar 18, 2008 1:08 am

Re: Transforms for creating a btConeTwistConstraint

Post by vagr »

Hi,

There are some pictures that may be helpful:

Page 184/298 in COLLADA 1.4.1 specification: http://www.khronos.org/files/collada_spec_1_4.pdf
Slide of presentation Physics in COLLADA: http://www.khronos.org/developers/libra ... s-2007.pdf

As my understanding, cone twist are two hinge constraints under different direction combined together. It is possible to create it generic constraint from setting two axis. If I am wrong, please correct me!

I have two questions as well:

1. Why constraint between PELVIS and SPINE is hinge, not cone_twist?
2. If in physics engine, we should always use world coordinates. Why in bullet, when setting constraint, local frame is applied? For example, here is the code from RagdollDemo in bullet engine:

localA.setIdentity(); localB.setIdentity();
localA.getBasis().setEulerZYX(0,M_PI_2,0); localA.setOrigin(btVector3(btScalar(0.), btScalar(0.15), btScalar(0.)));
localB.getBasis().setEulerZYX(0,M_PI_2,0); localB.setOrigin(btVector3(btScalar(0.), btScalar(-0.15), 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;
m_ownerWorld->addConstraint(m_joints[JOINT_PELVIS_SPINE], true);

Thanks,
vagr
Posts: 13
Joined: Tue Mar 18, 2008 1:08 am

Re: Transforms for creating a btConeTwistConstraint

Post by vagr »

Official documentation address:

http://www.continuousphysics.com/mediaw ... e=Download

And link for user manual: http://www.continuousphysics.com/ftp/pu ... Manual.pdf

Link for API: http://www.continuousphysics.com/Bullet/BulletFull

Is documentation updated?
vagr wrote:Hi,

There are some pictures that may be helpful:

Page 184/298 in COLLADA 1.4.1 specification: http://www.khronos.org/files/collada_spec_1_4.pdf
Slide of presentation Physics in COLLADA: http://www.khronos.org/developers/libra ... s-2007.pdf
I was wrong, cone and twist is a special point to point constraint that adds cone and twist axis limits. (page 13/28, bullet user manual). So in general, you got 3 axises, let's assume them as X, Y, Z. Tow for cone and one for twist. A easy example is your waist, which can move as a cone and then twist along axis from feet to head. And you need to set anchor for this joint as well. So in fact, it is composed of 4 constraints:

1. Point 2 Point (or Ball and Socket in ODE)
2. Hinge with axis along X
3. Hinge with axis along Y
4. Hinge with axis along Z
As my understanding, cone twist are two hinge constraints under different direction combined together. It is possible to create it generic constraint from setting two axis. If I am wrong, please correct me!
I guess that twist in RagDoll effect is not important. There could be a little bit but most action is from rotation along positive X, (from right to left?).
1. Why constraint between PELVIS and SPINE is hinge, not cone_twist?
I need help on this question because that we are using ODE now and COLLADA physics is similar to bullet engine. So could anyone tell me relation between local transformation set up and set up as world axis directly?
2. If in physics engine, we should always use world coordinates. Why in bullet, when setting constraint, local frame is applied? For example, here is the code from RagdollDemo in bullet engine:

localA.setIdentity(); localB.setIdentity();
localA.getBasis().setEulerZYX(0,M_PI_2,0); localA.setOrigin(btVector3(btScalar(0.), btScalar(0.15), btScalar(0.)));
localB.getBasis().setEulerZYX(0,M_PI_2,0); localB.setOrigin(btVector3(btScalar(0.), btScalar(-0.15), 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;
m_ownerWorld->addConstraint(m_joints[JOINT_PELVIS_SPINE], true);

Thanks,
eddybox
Posts: 25
Joined: Thu Nov 29, 2007 7:08 pm

Re: Transforms for creating a btConeTwistConstraint

Post by eddybox »

DigitalGhost, [cool model, btw]

First of all, there was a bug in the btConeTwistConstraint class that Marcus Hennix found and has a fix for. I'm not sure if it made its way into version 2.67, but it wasn't in 2.66. Line 146 (or thereabouts) of btConeTwistConstraint.cpp should read:

btScalar EllipseAngle = btFabs(swing1*swing1)* RMaxAngle1Sq + btFabs(swing2*swing2) * RMaxAngle2Sq;
rather than
btScalar EllipseAngle = btFabs(swing1)* RMaxAngle1Sq + btFabs(swing2) * RMaxAngle2Sq;

As for the role of the transforms in the constraint constructor, they describe the constraint's transform wrt each of the bodies' local spaces. Using these, you could - for instance - have the constraint align the y-axis of one body with the x-axis of another.

The easiest way to visualize/explain it is to, for a moment, think of the constraint and your bodies in world space. Once these are chosen, you can build the constraint as follows:

btXXXConstraint(
[btRigidBody&] childBody, // (eg. ragdoll shin)
[btRigidBody&] parentBody, // (eg. ragdoll thigh)
[const btTransform&] childBodyWorldTransform.inverse() * constraintWorldTransform, // = constraint in child body space
[const btTransform&] parentBodyWorldTransform.inverse() * constraintWorldTransform, // = constraint in parent body space
);

You don't always want to think in these terms/spaces, but it's one way to ensure that the constraint transform matches from both bodies' perspective, eliminating any initial snapping.

As for the btConeTwistConstraint constraint, the twist axis is along x, swing1 is along z, and swing2 is along y. (I think. This was deduced via trial and error. I agree with you that some documentation is needed here.)
Also, I've found the default values in the setLimit() method to be a little unstable. I don't understand their meaning yet, but I've had better luck when lowering the _softness and _biasFactor values by 50% or more.

Overall, I've found the btConeTwistConstraint to be a little shaky/unstable (particularly with tight limits) compared to Bullet's other constraints. That said, it's a very useful constraint type for ragdoll joints. Hopefully some improvements are in the pipe...

Hope this helps. And feel free to correct me (anyone) if any of this is wrong.
Cheers,
Eddy
eddybox
Posts: 25
Joined: Thu Nov 29, 2007 7:08 pm

Re: Transforms for creating a btConeTwistConstraint

Post by eddybox »

One more thing I just noticed. The following code at the beginning of the btConeTwistConstraint constructor is a bit odd:

// flip axis for correct angles
m_rbBFrame.getBasis()[1][0] *= btScalar(-1.);
m_rbBFrame.getBasis()[1][1] *= btScalar(-1.);
m_rbBFrame.getBasis()[1][2] *= btScalar(-1.);


When using the constructor in the way I mentioned in the previous post, I also need to "undo" the above basis change (by commenting out this code, or pre-flipping to cancel the flip). Otherwise my constraint ends up... flipped.

Hope this helps.
Eddy
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA

Re: Transforms for creating a btConeTwistConstraint

Post by Erwin Coumans »

Hi Eddy,

If you make your suggested changes, the RagdollDemo doesn't work anymore.

Can you verify? Do you have a suggested patch that is compatible with the RagdollDemo?
Hopefully some improvements are in the pipe...
If you can provide some reproduction test case, we can check it out and try to improve it.

Thanks,
Erwin
eddybox
Posts: 25
Joined: Thu Nov 29, 2007 7:08 pm

Re: Transforms for creating a btConeTwistConstraint

Post by eddybox »

I just submitted a patch to fix some of the known problems (mostly taken from LvR's and Marcus's suggestions, thanks):
http://code.google.com/p/bullet/issues/detail?id=47

It contains a fix for:
- the quaternion inverse
- a btHingeConstraint constructor
- the btConeTwistConstraint swing calculation bug
- the btConeTwistConstraint axis flipping. Specifically, I removed the flipping and updated RagdollDemo.cpp so the bone-constraint-spaces are consistent.

DigitalGhost, feel free to apply it locally and let me know if it works better for you now.

Cheers,
Eddy
Digitalghost
Posts: 25
Joined: Thu Dec 20, 2007 4:03 am

Re: Transforms for creating a btConeTwistConstraint

Post by Digitalghost »

hey Eddy,

Thanks for your help! I switched to point-to-point constraints awhile back, but I will revisit this shortly.
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA

Re: Transforms for creating a btConeTwistConstraint

Post by Erwin Coumans »

Just to confirm, the changes/fixes by Marcus and Eddy were included in Bullet 2.69.

Thanks for the help!
Erwin