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);
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:
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.
body->getInvInertiaTensorWorld().inverse()*(body->getWorldTransform().getBasis()*torque)
After a long period of frustration, I finally got body-local torque to work using the above as the input to applyTorqueImpulse (or applyTorque). I don't pretend to understand why it works at this point, but it does.
From Bullet:
void applyTorqueImpulse(const btVector3& torque)
{
m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor;
}
Maybe this is what tzenes was mentioning about producing the axis aligned torque. But I am puzzled that I can find no example of anyone else doing it this way. Surely someone else has wanted torque applied in the body's local space? But nothing I found online worked at all, despite it looking like it should.
If you only apply transform*torque, it'll look like it works at first, until you start moving away from the origin of your world. So if it feels harder to rotate the further you are away from the origin, or if things start rotating in reverse depending on where the body is, this is probably your problem.
EDIT: Oh, and here's how I have my translations:
btVector3 m = body->getWorldTransform().getBasis()*btVector3(strafe,move,rise);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With