Applying torque to bring y-axis back to world y-axis.

DerHeiligste

22-09-2008 11:44:23

Hi all,

So, having gotten past all the fun issues of compilation, I've begun work on my favorite project (now on its fourth incarnation), a fly-zapper simulator.

My flies have two states, FLYING and IDLE. In the preStep method of my StepListener, each fly checks its inputs (following the example of the PreFab Vehicle) and adds up some forces and torques. The inputs control the local pitch and yaw torques, and any raw contributes just a little roll, making the fly lean into the turn.

This all is working well, but I'd like to apply torques that slowly bring the pitch and roll back to zero. So, I get the orientation from the body and add countering x torque for the pitch and countering z torque for the roll. This works perfectly (aside from some wobble due to over-correction) when the fly hasn't had any yaw applied, is in-effective with 90 degrees of yaw in either direction, and works completely backwards with 180 degrees of yaw.

One solution to the problem is to gett the target orientation and Quaterion::Slerp between it and the current orientation, but I'd like to work within the confines of the physics simulator.

Is there a quaternion-savvy way to accomplish this? Also, I know F = ma, so I always multiply my desired acceleration by my mass to get a force. I don't understand torque nearly so well. Should my torque equations also include mass?

if (state == IDLE && goUp) {
body->wake();
body->setLinearVelocity(Ogre::Vector3(0.0f, 0.02f, 0.0f));
body->setAngularVelocity(Ogre::Vector3::ZERO);
state = FLYING;
giveStats = true;
adoptAnimation ("fly");
}

// Thrust

if (goForward) {
body->addRelativeForce(Ogre::Vector3(0.0f, 0.0f, 0.2f * mass));
}

// Angular velocity

float x = 0.0f, y = 0.0f, z = 0.0;

if (goLeft) y += 0.2f;
if (goRight) y -= 0.2f;
if (goUp) x -= 0.2f;
if (goDown && state == FLYING) x += 0.2f;

z -= y / 2.0f; // Lean into turns

// Slowly restore Y-axis.

Ogre::Quaternion o = body->getOrientation();

x -= o.getPitch().valueRadians() * 0.1;
z -= o.getRoll().valueRadians() * 0.1;

body->addRelativeTorque(Ogre::Vector3(x, y, z));

if (state == FLYING) {
// Cancel gravity
body->addForce(Ogre::Vector3(0.0f, 10.0f * mass, 0.0f));
}

DerHeiligste

24-09-2008 06:13:25

Well... I've got a solution going now. but it's still a little strange.

What I'm doing is taking the orientation and first undoing its yaw, then querying its pitch and roll, and using these to apply absolute rather than relative torque.

So, at least I've got something that works for now, but I feel like a smart person would look at my code and really scratch their head wondering why I'm doing it the way I'm doing it.

// Angular velocity

Ogre::Vector3 av = body->getAngularVelocity();

float x = 0.0f, y = 0.0f, z = 0.0;

if (goLeft) y += 0.2f;
if (goRight) y -= 0.2f;
if (goUp) x -= 0.2f;
if (goDown && state == FLYING) x += 0.2f;

z -= y / 1.2f; // Lean into turns

// Slowly restore Y-axis.

Ogre::Quaternion o = body->getOrientation();
Ogre::Quaternion unyaw(o.getYaw(), Ogre::Vector3::NEGATIVE_UNIT_Y);
Ogre::Quaternion o2 = o * unyaw;

body->addRelativeTorque(Ogre::Vector3(x, y, z));

x = (av.x + o2.getPitch().valueRadians()) * -0.1;
z = (av.z + o2.getRoll().valueRadians()) * -0.1;

body->addTorque(Ogre::Vector3(x, 0.0f, z));