Problem Understanding Quaternions

I’m trying to get my head around what exactly Quaternion.LookRotation does since the documentation is vague.

If I create a zx (horizontal) ground plane and create a stick like game object on it (like a clock hand) I can easily get that stick to face a target pos using:

Vector3 toTarget = target.transform.position - transform.position;
		
Quaternion newRot = Quaternion.LookRotation(toTarget, Vector3.up);
		
transform.rotation = newRot;

This makes sense since I’m reading that function (perhaps incorrectly) as rotating the stick around the up vector to face in the direction of toTarget.

If I create an xy (vertical) plane and position a stick on it I’d expect to be able to rotate that stick by using this:

Vector3 toTarget = target.transform.position - transform.position;
    		
Quaternion newRot = Quaternion.LookRotation(toTarget, Vector3.forward);
    		
transform.rotation = newRot;

Alas that does all sorts of weird stuff. The stick is rotated along all axis instead of just the the z axis. I can correct it by setting the x and y components of newRot to zero before applying it to the transform but I don’t understand why i should have to – why it should behave differently to the first example.

I’ve searched around a bit but I cannot find anything that explains what’s happening here. Can someone help me?

LookRotation will always rotate the object into the direction you give. The upvector just specifies where the y-axis will point to. You’re not rotating around the upvector, you’re rotating around the look-vector. I’m not sure where your target is. if it’s on the plane it should work your way. You may invert the Vector3.forward vector if the stick is rotated around the lookvector by 180°. Also it would be better to use a vector from the plane space as up vector. Use .forward / .up / .right of the planes transform.


edit

Where does the local axis of your plane point at? If you use the default plane that comes with Unity the face will look at the local up vector (y-axis)

If you use the plane’s upvector as upvector it should work, no matter how you rotate your plane as long as the target is on the plane.

Transform target; // assign the target object
Transform plane; // assign the plane

void Update()
{
    Vector3 toTarget = target.position - transform.position;
    Quaternion newRot = Quaternion.LookRotation(toTarget, plane.up);
    transform.rotation = newRot;
}

When you assign a new rotation to a transform, it replaces the original one. If the object was originally rotated in order to face what you consider its forward direction, then assigning a new rotation will make it loose the original setup, and it will be left looking to the wrong side. If this is the case, you should save the initial rotation in Start, then always multiply this rotation to the new one before assignment:

Quaternion rot0;

function Start(){
  rot0 = transform.rotation;
}

// apply the new rotation combined with the original one:
  transform.rotation = rot0 * newRot;

NOTES:

1- Quaternion operations aren’t commutative: don’t change the order, or you can have weird results.

2- I’m a JS guy, thus forgive me for any eventual C# error.

3- More details about quaternion multiplication at:
http://unity3d.com/support/documentation/ScriptReference/Quaternion-operator_multiply.html