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 );
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?

  • \$\begingroup\$ 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? \$\endgroup\$
    – SmoCoder
    Apr 17, 2015 at 11:59
  • \$\begingroup\$ 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. \$\endgroup\$
    – Nairou
    Apr 17, 2015 at 13:33
  • \$\begingroup\$ 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. \$\endgroup\$
    – Nairou
    Apr 17, 2015 at 14:53

1 Answer 1

//Everything normalized
shipRight = shipForward.Cross(target.Up);
shipUp = shipForward.Cross(shipRight);

The cross-product is perpendicular to both vectors. For this diagram, I gave both spheres random orientations. The left view shows the steps from an arbitrary, third, perspective; I couldn't find a better alignment, so you'll have to take my word that the cross product vectors are at right angles. The right view shows the apparent alignment of the "ups" looking along shipForward.

enter image description here


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .