LookAt函数的定义如下
void LookAt(Transformtarget,Vector3worldUp = Vector3.up);
根据官方的文档描述,该函数的功能是,旋转自身,使得当前对象的正z轴指向目标对象target所在的位置。
而对于worldUp的描述是,在完成上面的旋转之后,继续旋转自身,使得当前对象的正y轴朝向与worldUp所指向的朝向一致。这里所说的朝向一致并不是指两个向量方向完全一致,这就是让人迷惑的地方。
现使用一个例子进行解析
使摄像头指向一个物体,摄像头的位置是(0,30,60),目标物体的位置是(0,0,0),代码如下
using UnityEngine; using System.Collections; public class lookAtTest : MonoBehaviour { // Use this for initialization public Transform target; void Start () { target.position = Vector3.zero; transform.position = new Vector3(0, 30, 60); Vector3 diff = target.position - transform.position; transform.LookAt(target); } }
现在为了解析LookAt函数的计算过程,使用如下代码:
using UnityEngine; using System.Collections; public class lookAtTest : MonoBehaviour { public Transform target; void Start () { target.transform.position = Vector3.zero; transform.position = new Vector3(0, 30, 60); Vector3 diff = target.position - transform.position; Quaternion q = Quaternion.FromToRotation(Vector3.forward, diff); Vector3 newUp = q * Vector3.up; Quaternion qNew = Quaternion.FromToRotation(newUp,Vector3.up); transform.rotation = qNew * q; } }
该计算过程中,q的计算是正确的,qNew的计算是将新旋转后的y轴旋转到Vector3.up,经过这样运算后和前面LookAt的运行结果比对可以发现该计算是错误的。错误发生在qNew的计算上。
经过多次测试后发现,worldUp的描述“在完成上面的旋转之后,继续旋转自身,使得当前对象的正y轴朝向与worldUp所指向的朝向一致”里的朝向一致,指的是新旋转后的y轴与worldUp在该对象初次旋转后的xy平面上的投影向量一致。也就是说,worldUp应取它在应用了旋转量q后的xy平面的投影量。
新代码如下
using UnityEngine; using System.Collections; public class lookAtTest : MonoBehaviour { public Transform target; void Start() { target.transform.position = Vector3.zero; transform.position = new Vector3(0, 30, 60); Vector3 diff = target.position - transform.position; Quaternion q = Quaternion.FromToRotation(Vector3.forward, diff); Vector3 n = q * Vector3.forward; Vector3 worldUp = Vector3.up; float dirDot = Vector3.Dot(n, worldUp); Vector3 vProj = worldUp - n * dirDot; //worldUp在xy平面上的投影量 vProj.Normalize(); float dotproj = Vector3.Dot(vProj, newUp); float theta = Mathf.Acos(dotproj) * Mathf.Rad2Deg; Quaternion qNew = Quaternion.AngleAxis(theta, n); Quaternion qall = qNew * q; transform.rotation = qall; } }