Bullet Physics - Apply Torque Impulse in Body's Local Space

Lusid picture Lusid · Nov 4, 2009 · Viewed 8.8k times · Source

I'm currently evaluating the Bullet Physics Library for a 3D space game I'm writing using C++ and Ogre3D. I've gotten Ogre3D and Bullet integrated nicely by deriving from btMotionState and plugging in my SceneNodes, but now I'm having a lot of trouble calculating what values I should pass to btRigidBody::applyCentralImpulse and btRigidBody::applyTorqueImpulse methods in order to achieve the results I'm looking for.

When I press the LEFT or RIGHT keys on the keyboard, I want the spaceship to roll on the local Z axis. When I press UP or DOWN, I want it to pitch on the local X axis. When I press A or Z, I want it to accelerate/decelerate in the direction of the local Z axis. I can achieve this perfectly in Ogre using some quaternion mathematics and applying the translate/rotation directly on the SceneNode, but I really want to apply these values in the Bullet engine using the force/torque methods so it will continue to move/pitch/roll even after the user stops pressing keys, and so friction will act on the object to slow it down as necessary.

So, how do I calculate the necessary values to provide to these two impulse methods in order to ensure that the impulse acts based on the body's current orientation instead of using the world's axes?

Thanks, Marc

Update:

I was able to work out the impulses needed for forward and backward movement, but I am still struggling with how to reorient yaw/pitch/roll values in order to use them with the torque impulse method. Here's how I did the forward/backward movement:

if (mKeyboard->isKeyDown(OIS::KC_A))
    mBody->applyCentralImpulse(mBody->getWorldTransform().getBasis().getColumn(2) * 20 * time);
if (mKeyboard->isKeyDown(OIS::KC_Z))
    mBody->applyCentralImpulse(mBody->getWorldTransform().getBasis().getColumn(2) * -20 * time);

Answer

tzenes picture tzenes · Nov 5, 2009

So looking at btRigidBody.h

I notice the following code:

     void applyTorqueImpulse(const btVector3& torque)
     {
                     m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor;
     }

Now as I understand it, you want your Torque to be equal to some constant times the rotational vector around the x (or z) axis associated with your spaceship.

As we know the generalized rotation matrix can be determined as follows:

  1. Rotate to Align Axis Preform
  2. Rotation about canonical Axis
  3. Inverse of step 1

This means that if you can identify an axis aligned torque (which I don't know off the top of my head) you can transform it with your:

mBody->getWorldTransform()*axisAlignedXTorque

Which according to http://www.bulletphysics.com/Bullet/BulletFull/classbtTransform.html the * operator here is overridden to preform the world transform on the Torque vector.