Calculate 3D "up" vector to align ship to an arbitrary axis

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?

• What do you mean by "upright relative to" the target? Do you want the ship to roll to the same up vector that the target has? Like if you look from inside the ship, do you want your floor to align to their floor? Apr 17, 2015 at 11:59
• Kind of. It is hard to explain. The target is a stationary object aligned to the world axis, not arbitrarily positioned like the ship, so the ship's up vector should roll to face the chosen world axis. But because the ship could be anywhere, the up vector won't exactly match the chosen axis. If the ship is higher than the target, it will be aiming downward to point at the target. Kind of like as if there was gravity, you can look towards the floor but you are still relatively upright. So the ship's up vector will be as close to the target's up vector as it can be, given the aim vector. Apr 17, 2015 at 13:33
• Put another way: I want to roll the ship's up vector to match the target's up vector, without changing the arbitrary angle the ship is pointed in. The target's up vector is always aligned to a primary world axis (X/Y/Z), so I had assumed that would simplify things. Apr 17, 2015 at 14:53

//Everything normalized