public static Quaternion LookRotation (Vector3 forward, Vector3 upwards= Vector3.up);
官方解释:
使用指定的 forward 和 upwards 方向创建旋转。
Z 轴将与forward对齐,X 轴与 forward 和 upwards 之间的差积对齐,Y 轴与 Z 和 X 之间的差积对齐。 如果
forward 或 upwards 量值为零,则返回恒等。 如果 forward 和 upwards 共线,则返回恒等。

文档写得很官方,自己研究了一会,总的来说,
LookRotation的作用就是将方向转化为旋转角度:传入一个方向将返回一个旋转角,当某个物体被施加这个旋转角后,这个物体的forward方向将指向传入的方向。
这个方法常常配合transform.rotation = Quaternion.LookRotation()使用
 


实验演示:

搭建场景,编写脚本

实验内容:在场景中新建一个正方体和球体,用LookRotation方法将正方体“看向”球体,并绘制输出3条射线。
场景物体摆放
本文中所有脚本挂载在正方体

public class Test: MonoBehaviour{
    public Transform sphere;

    void Update(){
        Vector3 dir = sphere.position - transform.position;  //正方体指向球体的向量dir = 球体坐标 - 正方体坐标
        Quaternion ang = Quaternion.LookRotation(dir);  //创建一个 使正方体朝向球体的旋转角
        transform.rotation = ang;  //使正方体朝向球体

        Debug.DrawRay(transform.position, transform.forward * 100, Color.blue);  //绘制正方体forward
        Debug.DrawRay(transform.position, dir, Color.green);  //绘制向量dir
        Debug.DrawRay(transform.position, ang.eulerAngles, Color.red);
    }
}

运行场景,单参数解析:

场景运行Gif
蓝色射线:以正方体的forward为方向,与绿色射线部分重叠。
绿色射线:以欧拉角dir = sphere.position - transform.position为方向。
红色射线:以四元数LookRotation(dir).eulerAngles方向,直接绘制很奇怪且无意义。
由上我们可以分析得出:LookRotation()传入一个Vector3方向将返回一个Quaternion旋转角,某个物体被施加这个旋转角后,这个物体的forward方向将对齐传入的Vector3方向。
 

升级场景,双参数解析

由上我们得知,LookRotation的第一个参数将指定正方体的forward方向,而LookRotation的第二个参数upwards将指定正方体的up和right的方向(即Z轴旋转)。为方便演示,引入圆锥体cone并修改代码如下:

public class Test: MonoBehaviour{
    public Transform sphere;
    public Transform cone;

    void Update(){
        Vector3 dir = sphere.position - transform.position;
        Quaternion ang = Quaternion.LookRotation(dir, cone.up);  //传入第二个参数为cone.up
        transform.rotation = ang;

        Debug.DrawRay(transform.position, transform.forward * 100, Color.blue);
        Debug.DrawRay(transform.position, dir, Color.green);
        Debug.DrawRay(transform.position, ang.eulerAngles, Color.red);
		Debug.DrawRay(cone.position, cone.up, Color.green);  //绘制cone.up方向的绿射线
		Debug.DrawRay(cone.position, Vector3.Cross(cone.up, transform.forward), Color.red);  //绘制圆锥up方向与正方体forward方向的叉乘方向的红射线
    }
}

叉乘
任意调节圆锥的旋转,效果如下图:
演示
圆锥绿色射线:以cone.up为方向。
圆锥红色射线:以Vector3.Cross(transform.forward, cone.up)为方向。
由上图可看出,无论怎么旋转圆锥,圆锥红色射线正方体红色箭头始终方向相同,即圆锥红色射线指定了正方体right的方向。而圆锥绿色射线正方体绿色箭头并不方向相同,但呈现出了始终共面的特点。
由上我们可以分析得出:若指定第二个参数upwards,则物体的right方向将对齐‘第一个参数’与‘第二个参数’的叉乘方向。


代码手动实现LookRotation()通过三角函数求角度

    public Quaternion LookRotation(Vector3 forward)
    {
        float x = Mathf.Acos(Mathf.Sqrt((forward.x * forward.x + forward.z * forward.z) / (forward.x * forward.x + forward.y * forward.y + forward.z * forward.z))) * Mathf.Rad2Deg;
        if (forward.y > 0) x = 360f - x;

        float y = Mathf.Atan2(forward.x, forward.z) * Mathf.Rad2Deg;
        if (y < 0 || forward.x < 0) y += 180f;

        return Quaternion.Euler(x, y, 0f);
    }

这样一个简单的单参数LookRotation就实现了,如还需实现双参数的方法,还需求出transform.up与LookRotation()返回值之间的夹角。已知两向量求其夹角的公式:
θ = atan ⁡ 2 ( ( A ⃗ × B ⃗ ) ⋅ norm ⁡ ( ) , A ⃗ ∗ B ⃗ ) \begin{matrix} \theta = \operatorname{atan} 2((\vec{A} \times \vec{B}) \cdot \operatorname{norm}(), \vec{A} * \vec{B}) \end{matrix} θ=atan2((A ×B )norm(),A B )
但可惜LookRotation()方法内部没法直接拿到transform.up的值,虽然可以通过计算欧拉角的方式间接的求出transform.up,但具体实现过程会变得非常复杂,而且会有万向节死锁问题,暂无法分享示例代码。
LookRotation函数在Unity内部是用C++实现的,然后通过P/Invoke在C#中调用,因此我们无法知晓它的实际源码。而上述代码和码思路仅用于学习和理解LookRotation()的工作原理,实际项目中应该直接使用Unity内置的LookRotation()函数,因为它是经过充分测试和优化的。

Logo

这里是一个专注于游戏开发的社区,我们致力于为广大游戏爱好者提供一个良好的学习和交流平台。我们的专区包含了各大流行引擎的技术博文,涵盖了从入门到进阶的各个阶段,无论你是初学者还是资深开发者,都能在这里找到适合自己的内容。除此之外,我们还会不定期举办游戏开发相关的活动,让大家更好地交流互动。加入我们,一起探索游戏开发的奥秘吧!

更多推荐