I'm writing a script to control the movement of a 3D ship in a game. Given the ship's position and the coordinates of the destination, I've successfully calculated the Yaw and Pitch necessary to aim the ship at the target.
The part I haven't figured out is Roll. In addition to the target coordinates, I'd like to specify that the ship's "up" vector be aligned on a particular axis (X, Y, Z, positive or negative). Since the target coordinates could be anywhere, the ship will never be perfectly aligned on an axis, but I'd like to calculate the "up" vector for the ship that is the closest it can get to being aligned to that axis.
Essentially, I want to rotate the ship to point at the target, and also ensure that the ship is "upright" relative to the target.
The closest I've gotten is something like this:
Vector3D upVector; // The ship's normalized "up" vector
Vector3D rollVector = new Vector3D( upVector[0], upVector[1], 0 );
rollVector.Normalize();
float shipRoll = (float)Math.Acos( rollVector.Dot( new Vector3D(0, 1, 0) ) );
if ( upVector[0] < 0 ) {
shipRoll *= -1;
}
This almost works, for certain axis, but not well enough. The ship rolls to approximately the right angle, but then rocks back and forth, trying to reach perfect alignment to the axis. Which is impossible given the ship's arbitrary rotation. I think I'm just not understanding it well enough.
I think what I need to do is calculate the correct vector, given the ship's rotation, and roll into that, rather than just trying to roll towards the axis itself. But how would I calculate that for an arbitrary axis?