Quatenion.RotateTowards Ignoring "Up" Direction

I’m trying to get a spaceship to approach the player ship in a certain direction. To do that, I create a targetRoll quaternion using LookRotation. I then apply

transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRoll, rollSpeed * Time.deltaTime);

to make it look the correct way. When it stops moving, the front end of the ship is facing the same direction as targetRoll times Vector3.forward, but the top of the ship is NOT facing the same direction as targetRoll times Vector3.up.

Should I be using Lerp or Slerp? I’ve tried that, but it doesn’t seem to fix the problem, and they don’t play well with my method for calculating the current targetRoll.

For me at least 50% of answering rotation questions is figure out what people mean and need. There are a couple of ways to interpret your question. You cannot really both look at an object and perfectly align the up vectors. What you can do, is project the up vector of the target on the plane defined by the look vector and align the projected direction with the up vector. Here is a test script. Create two game object in a new scene. Mark them so you can tell the forward and the up of each object. Make one the target, put this script on the second. Click on the mouse to cause the second to look at and align the up with the target.

#pragma strict

var isRotating = false;
var target : Transform;
var speed = 55.0;

function Update() {
	if (Input.GetMouseButtonDown(0)) {
		DoTheLook();	
	}
}

function DoTheLook() {
    
    if (isRotating) return;
    isRotating = true;
    var dir = target.position - transform.position;
	var q = Quaternion.LookRotation(dir);
	dir.Normalize();
	if (Mathf.Abs(Vector3.Dot(dir, target.up)) < 0.99) {
		var distance = -Vector3.Dot(dir, target.up);
		var desiredUp = target.up + dir * distance;
		Debug.DrawRay(transform.position, desiredUp * 5.0, Color.red, 5.0f);
		var newUp = q * Vector3.up;
		q = Quaternion.FromToRotation(newUp, desiredUp) * q;
	}
	
	while (transform.rotation != q) {
		transform.rotation = Quaternion.RotateTowards(transform.rotation, q, speed * Time.deltaTime);
		yield;
	}
    isRotating = false;
}

Note this line:

    if (Mathf.Abs(Vector3.Dot(dir, target.up)) < 0.99) {

This check makes sure the look direction is not directly down or directly up at the target. When the look is aligned with the target up, no ‘up’ alignment is possible.