LookRotation用法详解 Unity3d Quaternion.LookRotation实现原理

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);  //即:绘制正方体的旋转轴
    }
}

运行场景,第一个参数解析:

场景运行GifVector3 dir = sphere.position - transform.position;
Quaternion ang = Quaternion.LookRotation(dir);
绿色射线:以向量dir为方向。蓝色射线:以正方体forward为方向,与绿色射线部分重合。红色射线:以四元数ang为方向,直接绘制看似“奇怪”(实则正方体的旋转轴线)。

 
传入一个Vector3方向将返回一个Quaternion旋转角,某个物体被施加这个旋转角后,这个物体的forward方向将对齐至传入的Vector3方向。
 

场景升级,第二个参数解析

LookRotation的第二个参数upwards影响物体的up和right的方向(即影响Z轴旋转),继上续代码即:
transform.right == Vector3.Cross(sphere.postion - transform.postion, upwards).normalized;
transform.up == Vector3.Cross(sphere.postion - transform.postion, transform.right).normalized;

叉乘演示

transform.rotation = Quaternion.LookRotation(sphere.position - transform.position, cone.up);  //第二个参数cone.up将影响正方体的right、up方向

调节圆锥的Rotation属性正方体的right、up方向受到了影响,核心代码如上。
圆锥起点绿色射线:方向为圆锥的+Y轴,即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。
初始时,transform.up、LookRotation()返回值、Y轴一定是共面的,且transform.up ⊥ LookRotation()返回值,根据这两个条件联立方程我们就可以准确求出transform.up的值。
线性代数

猜你喜欢

转载自blog.csdn.net/weixin_44962938/article/details/121655174