aybiss
12-11-2007 07:35:15
Hi all,
I'm trying to do simple network play and want to calculate the torque required to rotate from my current orientation to some target orientation.
I'm not really down with quaternions so I just can't figure out what my torque should be. I can empirically figure out an appropriate force, I can do the damping and stuff (ie I can read omega and process accordingly), and I'm not concerned about what path I take, since I'm only doing this to correct physics drift.
All I need to know is: If I have two quaternions q1 and q2, how can I figure out what torque to apply *this frame* to push my object from an orientation of q1 *towards* an orientation of q2?
Thanks in advance for any help,
Aaron.
Tubez
12-11-2007 13:35:14
Game_Ender
12-11-2007 13:44:19
Quaternion interpolation won't work, you can't give OgreNewt a quaternion and say go. It would help you correct large differences by splitting the quaternion up, only correcting small pieces first.
Welcome to world of controls
. Anyways there are some very math heavy ways of doing this but I think I have a way which may work: (untested):
What it basically does is compare vectors representing the direction and rotation of the orientations. It then applies the torque perpendicular to the resulting rotation and direction vector pairs.
// This assumes -Z goes straight, +Y is up, and +X is right
// The direction the object normally points
Vector3 forward(-1 * Vector3::UNIT_Z);
// The direction to the right of the way we normally point
Vector3 right(Vector3::UNIT_X);
// These point along each quaternion
Vector actualDirection(q1 * forward);
Vector desiredDirection(q2 * forward);
// These vector represent the roll of each quaternion relative to the resting
// case
Vector actionRotation(q1 * right);
Vector desiredRotation(q2 * right);
// Determine the torque required to correct the direction difference
Vector3 directionTorque(actualDirection.crossProduct(desiredDirection));
directionTorque.normalize(); // Just to be safe
// Scale the torque based on difference (angle) between the two
Real directionError = Math::ACos(actualDirection.dotProduct(desiredDirection));
directionTorque *= directionError * directionGain;
// Do the same thing for rotation
Vector3 rotationTorque(actualRotation.crossProduct(desiredRotation));
rotationTorque.normalize();
Real rotationError = Math::ACos(actualRotation.dotProduct(desiredRotation));
rotationTorque *= rotationError * rotationGain;
// The final torque (should be in the world, not local coordinate frame)
Vector3 finalTorque(rotationTorque + directionTorque);
// Tweak the rotationGain and directionGain to tune the algorithm
aybiss
13-11-2007 02:43:21
I figured it out. For the benefit of anyone using my search terms here is the solution (in MOGRE code)
Quaternion rotError = theBody.Orientation.UnitInverse() * targetOri;
Matrix3 rotMat = rotError.ToRotationMatrix();
Radian r1, r2, r3;
rotMat.ToEulerAnglesXYZ(out r1, out r2, out r3);
currTorque =
new Vector3(r1.ValueRadians, r2.ValueRadians, r3.ValueRadians);
To explain, the difference between two quaternions is given by multiplying one by the inverse of the other. I discovered that quite by accident almost simultaneously to working out the other part.
We can get a rotation matrix from a quaternion. This can then be reoriented to the 'euler' axes, X, Y, and Z. By reading the angles from here and simply creating a torque vector proportional to it, we can achieve the desired effect.