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

2

19

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);
Fino answered 4/11, 2009 at 22:17 Comment(2)
Can you pass the quaternion to the impulse API or somehow convert the quaternion to something you can pass?Adonai
From what I can see in the API, it appears the linear impulse method only accepts an x,y,z vector of the direction in world coordinates, and the angular impulse method only accepts an y,p,r vector for the yaw, pitch, and roll in world coordinates. While the math may be slightly over my head (I have a hard time visualizing things like dot and cross products), the actual Bullet API itself is WAY over my head and completely new to me... the combination of these two is making my life impossible at the moment.Fino
F
3

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.

Floorage answered 5/11, 2009 at 21:27 Comment(0)
M
1
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);

Martinelli answered 11/5, 2013 at 23:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.