Transform.LookAt解析

LookAt函数的定义如下

void LookAt(Transformtarget,Vector3worldUp = Vector3.up);

target    :Object to point towards
worldUp:Vector specifying the upward direction.



根据官方的文档描述,该函数的功能是,旋转自身,使得当前对象的正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;

    }


}










你可能感兴趣的:(Transform.LookAt解析)