Character Controller date?

pico
Posts: 229
Joined: Sun Sep 30, 2007 7:58 am

Character Controller date?

Post by pico »

Hi Erwin,

first of all, we appreciate all your you hard work alot. Bullet is just great!

My question is about a (very rough) release date of the character controller you mentioned. Is this something planned for the next weeks or months? Or is something not directly planned? Then we need to find a custom solution (we tried already alot of things...).

Well, we have a project were we can't get away without limiting the possible rotations of a freely moveable character. To my knowledege this currently not possible in Bullet. I guess such limits would be a major part of a character controller. Indeed they would be helpfull for any rigidBody (keeping a moving vehicle from flipping over, etc).

Some type of cone limit (like the one used in KARMA physics (UE2) or Quake physics) would be very helpful.

Here some description (Karma):
============================
KConeLimit:
This is a special type of constraint because its location in the world does not mean anything. Its function is to limit rotation angles of objects to KHalfAngle and to do so with specified KStiffness and KDamping. The angle you set will limit rotation of the affected KConstraintActors to 0.5*KHalfAngle in either direction of the starting orientation. The important thing to note is that this constraint limits angle movements from its starting orientation. In other words, when the level starts, the actors (or more accurately their coordinate system) can only increase rotation by 0.5*KHalfAngle or decrease rotation by 0.5*KHalfAngle. If this angle is exceeded, the KStiffness will return it to its limits. If you set the KStiffness very strong objects will be stopped dead (more or less) upon reaching the limit. A very light force will cause a "springy" return to the limits.
============================
Dirk Gregorius
Posts: 861
Joined: Sun Jul 03, 2005 4:06 pm
Location: Kirkland, WA

Re: Character Controller date?

Post by Dirk Gregorius »

If you want to have a conical limit I could send you some sample code, but you would need to integrate into Bullet yourself. Would that work for you?
pico
Posts: 229
Joined: Sun Sep 30, 2007 7:58 am

Re: Character Controller date?

Post by pico »

Dirk Gregorius wrote:If you want to have a conical limit I could send you some sample code, but you would need to integrate into Bullet yourself. Would that work for you?
Hi Dirk,

could you please attach the code here? I think i can integrate it. Well, at least i will give it a try.

Thanks for your offer
Dirk Gregorius
Posts: 861
Joined: Sun Jul 03, 2005 4:06 pm
Location: Kirkland, WA

Re: Character Controller date?

Post by Dirk Gregorius »

Basically you have two vectors attached to both bodies. The angle between both should never grow larger than theta_max. The position constraint is:

C = u2 * u1 - cos( theta_max ) > 0

The Jacobian is:

J = ( 0 -u2 x u1 0 u2 x u1 )


Your constraint should look something like this;

Code: Select all

class ConicalLimit
{
enum State
{
AT_LIMIT,
FREE
};

State mState;

Body* mpBody1;			           
Body* mpBody2;			          

Vec3mLocalU1, mLocalU2;          	  

Vec3 mJacobianAxis;

float mEffectiveMassInv;                        
float mAngularImpulse;  
float mBias;

float mConeHalfAngle;                                           												   	
};
During construction you need to do the following:

Code: Select all

void ConicalLimit::Initialize( Body* b1, Body* b2, Vec3 axis, float theta_max )
{
// Save bodies
mpBody1 = b1;
mpBody2 = b2;

// Save axis in local body frames
mLocalU1 = mpBody1->TransformToBodySpace( axis );
mLocalU2 = mpBody2->TransformToBodySpace( axis );

// Store tha half angle
mConeHalfAngle = theta_max / 2.0f;

// Resest the accumulated impulse
mAngularImpulse = 0.0f;
}

In the prepare phaseyou you build the Jacbian (here only an axis), the effective mass and eventually warm-start (not sure if Bullet does/wants this):

Code: Select all

void ConicalLimit::Prepare( float dt )
{
Vec3 u1 = mpBody1->TransformToWorldSpace( mLocalU1 );
Vec3 u2 = mpBody2->TransformToWorldSpace( mLocalU2 );

float C = Vec3Dot( u2, u1 ) - Math::Cos( mConeHalfAngle + ALLOWED_ANGULAR_ERROR );
if ( c <= 0.0f )
{
// Save that we are at the limit
mState = AT_LIMIT;

// Bias
mBias = -0.2f * C / dt;

// Jacobian
Vec3Cross( mJacobianAxis, u2, u1 );                                                    
VALIDATE( !Vec3FuzzyZero( mJacobianAxis ) && "Degenerate Jacobian element" );      
               
// Effective mass                                                                                                                                                      
Vec3 x1 = Vec3Transform( mpBody1->GetGlobalInertiaInv(), mJacobianAxis );                    
Vec3 x2 = Vec3Transform( mpBody2->GetGlobalInertiaInv(), mJacobianAxis );                    
                                                                                                     
float K = Vec3Dot(mJacobianAxis , x1 ) + DYNvec3Dot( mJacobianAxis , x2 );     
VALIDATE( K > 0.0f && "Non-positive definite diagonal element" );                                
                                                                                                     
mEffectiveMassInv = 1.0f / K;                                                     
       
// Warmstart                                                                                              
Vec3 L;                                                                                           
Vec3Scale( L, mJacobianAxis , mAngularImpulse );                                        
                                                                                                     
mpBody1->ApplyAngularImpulse( -L );                                                                  
mpBody2->ApplyAngularImpulse(  L );                                                                  
}
else
{
// Reset if limit not violated
mState = FREE;
mAngularImpulse = 0.0f;
}

}


Now the satisfaction code becomes simple:

Code: Select all

void ConicalLimit::Satisfy( void )
{
if { mState == AT_LIMIT )
{
// Relative angular velocity
Vec3 w_rel = mpBody2->GetAngVel() - mpBody1->GetAngVel();

// Project onto Jacobian and add bias
float dw = mBias - Vec3Dot( w_rel, mJacobianAxis );

// Compute incremental impulse ( dL = -invK * d )
float dL = mEffectiveMassInv * dw;            
                                               
// Clamp against accumulated impulse
float L0 = mAngularImpulse;                   
mAngularImpulse = Math::Max( L0 + dL, 0.0f ) ;  
dL = L0 - mAngularImpulse;

// Apply the incremental impulse
Vec3 L;
Vec3Scale( L, mJacobianAxis, dL );

mpBody1->ApplyAngularImpulse( -L );
mpBody2->ApplyAngularImpulse(  L  );

}

}


HTH,
-Dirk
Dirk Gregorius
Posts: 861
Joined: Sun Jul 03, 2005 4:06 pm
Location: Kirkland, WA

Re: Character Controller date?

Post by Dirk Gregorius »

Note that I made a small change and added the bias (Baumgarte stabilization)...
pico
Posts: 229
Joined: Sun Sep 30, 2007 7:58 am

Re: Character Controller date?

Post by pico »

Dirk Gregorius wrote:Note that I made a small change and added the bias (Baumgarte stabilization)...
Thanks alot Dirk. This looks quite promising. I think this should be easily adoptable for just one body that wants to stay within certain degrees to the world axes.
Dirk Gregorius
Posts: 861
Joined: Sun Jul 03, 2005 4:06 pm
Location: Kirkland, WA

Re: Character Controller date?

Post by Dirk Gregorius »

All the constraints should be relative to the first body. I adopted the definition from Erin since it helps me to visualize things. It is also nice for angular limits or prismatic joints since you know that you measure the relative rotation or some linear displancement w.r.t. the first body.

Let me know if you run into any issues...


Cheers,
-Dirk
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA

Re: Character Controller date?

Post by Erwin Coumans »

pico wrote:My question is about a (very rough) release date of the character controller you mentioned. Is this something planned for the next weeks or months? Or is something not directly planned? Then we need to find a custom solution (we tried already alot of things...).
It depends on my schedule, I can't give an estimated date yet.

For now, I recommend one of the following options:

1) use an entirely non-physical character, by moving a kinematic object yourself, using collision detection.
2) use 'setAngularFactor' to keep the rigidbody standing up:

Code: Select all

//this prevents rotation due to collisions
rigidbody->setAngularFactor(0);
3) adding a hinge constraint in 'angular only mode' (without the position constraint)

Code: Select all

btHingeConstraint* hinge = new btHingeConstraint(...)
hinge->setAngularOnly(true);
If this doesn't work out, you can also modify the btConeTwistContrains in a similar way (without the position constraint), or follow Dirk Gregorius help with a custom constraint.

Thanks,
Erwin
pico
Posts: 229
Joined: Sun Sep 30, 2007 7:58 am

Re: Character Controller date?

Post by pico »

Erwin Coumans wrote:If this doesn't work out, you can also modify the btConeTwistContrains in a similar way (without the position constraint), or follow Dirk Gregorius help with a custom constraint.
Thanks Erwin.

I guess i misunderstood the btConeTwistConstraint as it already seem todo what i described above (i use it on a single body).

I now use:
coneTwistCnstr->setAngularOnly(true);
coneTwistCnstr->setLimit(PI, PI, PI_8);

This limits my X&Z axis to -PI/8 to PI/8. This is exactly what im looking for.

However, my objects now gets from time to time strong torque forces from the constraint solver. I guess this is from setting _swingSpan1 and _swingSpan2 to PI. Although i checked through the ragdoll examples im really not sure how those swingSpans are defined. Could you please outline it a bit? Or do i need to alter the other settings (like softness and bias) to make the contraint more stable.
Dirk Gregorius
Posts: 861
Joined: Sun Jul 03, 2005 4:06 pm
Location: Kirkland, WA

Re: Character Controller date?

Post by Dirk Gregorius »

IIRC you can look in the Ageia documentation for a definition of twist-swing decomposition. I would also try make the swing limit a little softer by allowing some very small rotation...
pico
Posts: 229
Joined: Sun Sep 30, 2007 7:58 am

Re: Character Controller date?

Post by pico »

Dirk Gregorius wrote:IIRC you can look in the Ageia documentation for a definition of twist-swing decomposition. I would also try make the swing limit a little softer by allowing some very small rotation...
I tried to vary the damping,bias and softness without luck.
I checked out their "swing-cone limit" documentation. Thanks for the tip. This is now more clear to me.

To see if the wrong torque is introduced from swing or twist i browsed through the btConeTwistConstraint source. When using swingSpans of 1 then the EllipseAngle is greater 1.0 and so the swingSpan constraint won't be calculated anymore. So only the twist component introduces the wrong torque. Maybe i have made a mistake in the rbAFrame? Must i setup somehow a special axis? I just used an identity matrix. Here is my code:

btTransform inA;
inA = btTransform::getIdentity();
cnstr=new btConeTwistConstraint(body, inA);
cnstr->setLimit(2, 2,PI/8);
cnstr->setAngularOnly(true);

Thanks for any help
User avatar
Erwin Coumans
Site Admin
Posts: 4221
Joined: Sun Jun 26, 2005 6:43 pm
Location: California, USA

Re: Character Controller date?

Post by Erwin Coumans »

Have you tried method 1,2 or 3, as mentioned earlier? I haven't seen a cone-twist constraint used to model a character controller.

Thanks,
Erwin
pico
Posts: 229
Joined: Sun Sep 30, 2007 7:58 am

Re: Character Controller date?

Post by pico »

Erwin Coumans wrote:Have you tried method 1,2 or 3, as mentioned earlier? I haven't seen a cone-twist constraint used to model a character controller.

Thanks,
Erwin
Hi Erwin,

my character is some kind of boat and floats in water. I guess its irritating when i call it a character ;) However, it needs some extra limits like a player character.

1+2) This does not work because my character needs to gets affected by buoyancy forces that are applied on him
3) The hinge does prevent the buoyancy forces to be applied

So the cone-twist is perfect. By just using a twist limit buoyancy forces can be applied, but they would never make the boat flip over. It already works very nice except that when moving around the constrain goes mad sometimes for a second or so.