Unity Quaternion quaternion commonly used API analysis and rotation interpolation animation implementation

1. Common APIs of Quaternion

Quaternion.FromToRotation(Vector3 fromDirection, Vector3 toDirection)

Official analysis: Creates a rotation which rotates from fromDirection to toDirection
Chinese meaning: Create a rotation from the form direction to the to target direction Imagine
a scene like this, we use the Quaternion.FromToRotation() API to convert the main object in the figure below What should the z-axis (blue axis) of (m_MainTran) face the target object (m_TargetTran).
insert image description here
the code

            //求出目标朝向
            Vector3 targetDir = m_TargetTran.position - m_MainTran.position;
            
            //求出m_MainTran.forward旋转到目标方向需要的旋转四元数
            Quaternion  q = Quaternion.FromToRotation(m_MainTran.forward, targetDir);
            
            //把求出来的旋转四元数应用到 forward 方向
            Vector3 finalDir = q * m_MainTran.forward; 
            
            //最后让主目标的 forward 朝向计算出来的方向
            m_MainTran.forward = finalDir;

Parsing is commented out. Next, look at the effect.
insert image description here
Similarly, if we want the x-axis of the main target to face the target, that is, the right direction. can be written like this

            //求出目标朝向
            Vector3 targetDir = m_TargetTran.position - m_MainTran.position;

            //求出m_MainTran.right旋转到目标方向需要的旋转四元数
            Quaternion q = Quaternion.FromToRotation(m_MainTran.right,targetDir);

            //把求出来的旋转四元数应用到 right 方向
            Vector3 finalDir = q * m_MainTran.right;

            //最后让主目标的 right 朝向计算出来的方向
            m_MainTran.right = finalDir;

Renderings
insert image description here
This is useful in 2D games. Because in 2D games we generally let the x or y of the object face the target, not the z axis

Quaternion.LookRotation(Vector3 forward, Vector3 upwards = Vector3.up)

  • Kanpo Analysis: Creates a rotation with the specified forward and upwards directions
  • Chinese meaning: create a rotation. Make the positive direction (z axis) of the target point to the target forward.
  • tip: When looking at the target, the y-axis can be above or below the z-axis. The second parameter is used here to control, if not filled, the default is above Vector.up. If you want to change the direction, you can use Vector.down

In the same scene, we use Quaternion.LookRotation() to make the target face the target direction, and the above code

            //求出目标方向
            Vector3 targetDir = m_TargetTran.position - m_MainTran.position;
            
            //计算出z轴朝向目标方向需要的旋转四元数
            Quaternion rotation =  Quaternion.LookRotation(targetDir,Vector3.up);
            
            //让m_MainTran.rotation等于求出的旋转
            m_MainTran.rotation = rotation;

Effect picture
insert image description here
It can be seen that the main object is also successfully facing the target. The rotation obtained by this method represents the rotation required for the Z axis to face the target direction. What if we want the X axis to face the target direction.

  • You can make your right equal to your forward after finding the result. Such as the following code
            Vector3 targetDir = m_TargetTran.position - m_MainTran.position;
            Quaternion rotation =  Quaternion.LookRotation(targetDir,Vector3.up);
            m_MainTran.rotation = rotation;
            
            //上面的代码会使z轴朝向目标。 这里在这基础上让 right 朝向 forward 就可以了
            m_MainTran.right = m_MainTran.forward;

renderings
insert image description here

2. Realization of rotation interpolation and animation

Quaternion.Lerp(Quaternion a, Quaternion b, float t)

  • 官文解析:Interpolates between a and b by t and normalizes the result afterwards. The parameter t is clamped to the range [0, 1]
  • Chinese meaning: Interpolate between two quaternions a and b, interpolation range t = [0~1]

We can use Quaternion.Lerp() to achieve rotation animation. Note that the parameters filled in here are quaternions. We can use the above Quaternion.FromToRotation() or Quaternion.LookRotation() to find the parameters we want.

Next, let's realize that the Z axis of the main target turns to the target direction within 2 seconds

    private bool isRotating = false;
    private float curTime = 0;
    private float AllTime = 3;

    private Quaternion oldQ;
    private Quaternion targetQ;
    
    // Update is called once per frame
    void Update()
    {
    
    
        if (Input.GetKeyDown(KeyCode.A))
        {
    
    
            isRotating = true;
            curTime = 0;
            
            //当前旋转
            oldQ = m_MainTran.rotation;
            //目标旋转
            targetQ = Quaternion.LookRotation(m_TargetTran.position - m_MainTran.position);
        }

        if (isRotating)
        {
    
    
            curTime += Time.deltaTime; 
            float t = curTime / AllTime;
            t = Mathf.Clamp(t, 0, 1);
            
            //用t进行插值
            Quaternion lerpQ = Quaternion.Lerp(oldQ,targetQ,t);
            //设置到目标旋转
            m_MainTran.rotation = lerpQ;

            Debug.Log($"{
      
      GetType()} curT:{
      
      t}");
            if (t >= 1)
            {
    
    
                isRotating = false;
            }
        }
    }

Effect diagram
Please add a picture description
Sometimes what we need is other axes, such as the X axis facing the target, so how to do it. Next, let's implement it, the code

    private bool isRotating = false;
    private float curTime = 0;
    private float AllTime = 3;

    private Vector3 oldDir;
    private Quaternion oldQ;
    private Quaternion targetQ;
    
    // Update is called once per frame
    void Update()
    {
    
    
        if (Input.GetKeyDown(KeyCode.A))
        {
    
    
            isRotating = true;
            curTime = 0;
            
            //记录起始点的朝向
            oldDir = m_MainTran.right;
            //起始插值参数(对于oldDir方向来说,起始不需要旋转。所以这里是Quaternion.identity)
            oldQ = Quaternion.identity;
            //目标插值参数
            targetQ = Quaternion.FromToRotation(m_MainTran.right, m_TargetTran.position - m_MainTran.position);
        }

        if (isRotating)
        {
    
    
            curTime += Time.deltaTime; 
            float t = curTime / AllTime;
            t = Mathf.Clamp(t, 0, 1);
            
            //用t进行插值
            Quaternion lerpQ = Quaternion.Lerp(oldQ,targetQ,t);
            //设置到目标旋转
            m_MainTran.right = lerpQ * oldDir;

            Debug.Log($"{
      
      GetType()} curT:{
      
      t}");
            if (t >= 1)
            {
    
    
                isRotating = false;
            }
        }
    }

Effect picture:
Please add a picture descriptioncomments are added to the code. Press the A key, we can see that our X axis has turned to the target

Quaternion.Slerp(Quaternion a, Quaternion b, float t)

This is spherical interpolation, and the animation effect may be better than Quaternion.Lerp().
The specific usage is the same as Quaternion.Lerp(), you only need to change Lerp() in the above code to Slerp() to see the effect. They are not listed here. You can replace it yourself.

Quaternion.RotateTowards(Quaternion from,Quaternion to,float maxDegreesDelta)

  • Official analysis: Rotates a rotation from towards to
  • Chinese meaning: turn the rotation from from to to. The angle of rotation is maxDegreesDelta, but the final rotation will not exceed to. So here is the theoretical maximum rotation angle.

You can look at the source code. In fact, Quaternion.SlerpUnclamped() is used to calculate it at the end. First find the total angle, then use
maxDegreesDelta / total angle as the interpolation t

    public static Quaternion RotateTowards(
      Quaternion from,
      Quaternion to,
      float maxDegreesDelta)
    {
    
    
      float num = Quaternion.Angle(from, to);
      return (double) num == 0.0 ? to : Quaternion.SlerpUnclamped(from, to, Mathf.Min(1f, maxDegreesDelta / num));
    }

With this method, we can specify the rotation angle to turn to the target. Next, let's try, the code

    private bool isRotating = false;
    private float perAngel = 15;//每秒转15度
    private Quaternion targetQ;
    
    // Update is called once per frame
    void Update()
    {
    
    
        if (Input.GetKeyDown(KeyCode.A))
        {
    
    
            isRotating = true;
            curTime = 0;
            
            //目标插值参数
            targetQ = Quaternion.LookRotation(m_TargetTran.position - m_MainTran.position);
        }
        
        if (isRotating)
        {
    
    
            //计算出每帧的旋转
            Quaternion rotQ = Quaternion.RotateTowards(transform.rotation,targetQ,perAngel * Time.deltaTime);
            //设置到目标旋转
            m_MainTran.rotation = rotQ;
            
            if (m_MainTran.rotation.Equals(targetQ))
            {
    
    
                isRotating = false;
                Debug.Log($"{
      
      GetType()} exit rot");
            }
        }
    }

Renderings:
Please add a picture description

Quaternion AngleAxis(float angle, Vector3 axis)

  • Kanpo analysis: Creates a rotation which rotates angle degrees around axis

  • Chinese meaning: create a rotation. Represents the axis direction as the rotation axis, the rotation angle angle

  • Using this method, we can rotate our orientation along any axis by any angle, exactly the way we want it.
    For example, in 2D games, we generally rotate along Vector.forward;
    in 3D space, which direction should we rotate along?

We can use the cross product to find the axis of rotation . The mathematical meaning of cross product : Vector c = Vector3.Cross(a,b); The calculated vector c is perpendicular to the plane formed by vectors a and b. This vector c is the rotation axis we want.

Next we use Quaternion.AngleAxis() to implement the previous rotation animation. upper code

    private bool isRotating = false;
    private float perAngel = 15;//每秒转15度
    private Vector3 rotAxis;
    
    // Update is called once per frame
    void Update()
    {
    
    
        if (Input.GetKeyDown(KeyCode.A))
        {
    
    
            isRotating = true;

            //求出旋转轴
            rotAxis = Vector3.Cross(m_MainTran.forward,m_TargetTran.position - m_MainTran.position);
        }
        
        if (isRotating)
        {
    
    
            //计算出每帧的旋转
            Quaternion rotQ = Quaternion.AngleAxis(perAngel * Time.deltaTime,rotAxis);
            //应用旋转
            m_MainTran.forward = rotQ * m_MainTran.forward;
            
            //如果旋转到只差2度,就旋转到目标方向,并退出旋转动画
            if (Vector3.Angle(m_MainTran.forward,m_TargetTran.position - m_MainTran.position) <= 2)
            {
    
    
                m_MainTran.forward = m_TargetTran.position - m_MainTran.position;
                isRotating = false;
                Debug.Log($"{
      
      GetType()} exit rot");
            }
        }
    }

Effect picture:
Please add a picture description
It can be seen that the main object has successfully turned to the target.

3. Conclusion

  • Quaternion is a relatively abstract concept, but mastering the above API, you can turn around as you like~

Guess you like

Origin blog.csdn.net/aaa27987/article/details/123093866