Unity Quaternion commonly used API parsing and rotation interpolation animation

Posted by jstinehelfer on Fri, 25 Feb 2022 09:42:39 +0100

1, Quaternion common API s

Quaternion.FromToRotation(Vector3 fromDirection, Vector3 toDirection)

Official analysis: creates a rotation which revolutions from fromdirection to todirection
Create a rotation from the form direction to the target direction
Imagine a scenario like this. Let's use quaternion From torotation() API, what should I do to orient the z axis (blue axis) of the main object (m_MainTran) in the following figure towards the target object (m_TargetTran).

code

            //Find the target orientation
            Vector3 targetDir = m_TargetTran.position - m_MainTran.position;
            
            //Find m_MainTran.forward the rotation quaternion required to rotate to the target direction
            Quaternion  q = Quaternion.FromToRotation(m_MainTran.forward, targetDir);
            
            //Apply the calculated rotation quaternion to the forward direction
            Vector3 finalDir = q * m_MainTran.forward; 
            
            //Finally, make the forward of the main target towards the calculated direction
            m_MainTran.forward = finalDir;

The parsing is annotated. Next, let's see the effect

Similarly, if we want the x-axis of the main target to face the target, that is, the right direction. It can be written like this

            //Find the target orientation
            Vector3 targetDir = m_TargetTran.position - m_MainTran.position;

            //Find m_MainTran.right the rotation quaternion required to rotate to the target direction
            Quaternion q = Quaternion.FromToRotation(m_MainTran.right,targetDir);

            //Apply the calculated rotation quaternion to the right direction
            Vector3 finalDir = q * m_MainTran.right;

            //Finally, make the right of the main target face the calculated direction
            m_MainTran.right = finalDir;

design sketch

This is useful in 2D games. Because in 2D games, we usually make the x or y of the object face the target, not the z axis

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

  • Official analysis: creates a rotation with the specified forward and upward directions
  • Create a rotation. Make the positive direction of the target (z-axis) 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. If it is not filled in, the default is vector Up above. If you want to change direction, you can use vector down

For the same scene, we use quaternion Lookrotation() to make the target face the target direction and the code on the target

            //Find the target direction
            Vector3 targetDir = m_TargetTran.position - m_MainTran.position;
            
            //Calculate the rotation quaternion required for the z-axis towards the target direction
            Quaternion rotation =  Quaternion.LookRotation(targetDir,Vector3.up);
            
            //Let m_MainTran.rotation is equal to the calculated rotation
            m_MainTran.rotation = rotation;

design sketch

It can be seen that the main object also successfully faces the target. The rotation obtained by this method represents the rotation required for the Z-axis towards 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 you get 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;
            
            //The above code will make the z-axis towards the target. On this basis, let right face forward
            m_MainTran.right = m_MainTran.forward;

design sketch

2, Rotation interpolation and animation implementation

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

  • Officials between a and B by T and normalizes the result after The parameter t is clamped to the range [0, 1]
  • Interpolation between quaternions a and b, interpolation range t = [0 ~ 1]

We can use quaternion Lerp() to realize the rotation animation. Note that the parameters filled in here are quaternions. We can use 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 in 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;
            
            //Current rotation
            oldQ = m_MainTran.rotation;
            //Target 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);
            
            //Interpolation with t
            Quaternion lerpQ = Quaternion.Lerp(oldQ,targetQ,t);
            //Set to target rotation
            m_MainTran.rotation = lerpQ;

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

design sketch

Sometimes what we need is other axes, such as X-axis facing the target. What should we do. Next, let's implement 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;
            
            //Record the orientation of the starting point
            oldDir = m_MainTran.right;
            //Initial interpolation parameter (for the oldDir direction, the initial does not need to be rotated, so here is Quaternion.identity)
            oldQ = Quaternion.identity;
            //Target interpolation parameters
            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);
            
            //Interpolation with t
            Quaternion lerpQ = Quaternion.Lerp(oldQ,targetQ,t);
            //Set to target rotation
            m_MainTran.right = lerpQ * oldDir;

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

design sketch:
Comments are added to the code. Press the A key and you 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 () is better.
Specific usage and quaternion Like Lerp(), you only need to change Lerp() in the above code to Slerp() to see the effect. It's not listed here. You can replace it yourself.

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

  • Official analysis: rotates a rotation from directions to
  • Turn the rotation from from to. The rotation angle is maxDegreesDelta, but the final rotation will not exceed to So this is the theoretical maximum rotation angle.

You can see the source code. In fact, quaternion is also used here Slerpunclamped(). First find the total angle, and then
maxDegreesDelta / total angle as 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 degrees per second
    private Quaternion targetQ;
    
    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            isRotating = true;
            curTime = 0;
            
            //Target interpolation parameters
            targetQ = Quaternion.LookRotation(m_TargetTran.position - m_MainTran.position);
        }
        
        if (isRotating)
        {
            //Calculate the rotation of each frame
            Quaternion rotQ = Quaternion.RotateTowards(transform.rotation,targetQ,perAngel * Time.deltaTime);
            //Set to target rotation
            m_MainTran.rotation = rotQ;
            
            if (m_MainTran.rotation.Equals(targetQ))
            {
                isRotating = false;
                Debug.Log($"{GetType()} exit rot");
            }
        }
    }

design sketch:

Quaternion AngleAxis(float angle, Vector3 axis)

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

  • Create a rotation. Represents the angle of rotation with the axis direction as the rotation axis

  • In this way, we can rotate our direction along any axis at any angle, and accurately rotate according to the effect we want.
    For example, in 2D games, we usually follow the vector Forward to rotate;
    In 3D space, which direction should we rotate?

We can use the fork to multiply the rotation. Mathematical meaning of cross multiplication: vector c = vector3 Cross(a,b); The calculated vector c is perpendicular to the plane formed by vectors a and B. We can use c as the axis of rotation.

Next, we use quaternion Angleaxis() to achieve the previous rotation animation. Upper code

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

            //Find the rotation axis
            rotAxis = Vector3.Cross(m_MainTran.forward,m_TargetTran.position - m_MainTran.position);
        }
        
        if (isRotating)
        {
            //Calculate the rotation of each frame
            Quaternion rotQ = Quaternion.AngleAxis(perAngel * Time.deltaTime,rotAxis);
            //Apply rotation
            m_MainTran.forward = rotQ * m_MainTran.forward;
            
            //If the rotation is only 2 degrees away, it rotates to the target direction and exits the rotation animation
            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");
            }
        }
    }

design sketch:

It can be seen that the main object has also successfully turned to the target. Quaternion is a relatively abstract concept, but if you master the above API, you can turn around as you like~

Topics: Unity UE4