Unity【Lerp & Slerp】-The difference between linear interpolation and spherical interpolation

        In Unity's vector Vector and quaternion Quaternion classes, there are linear interpolation Lerp and spherical interpolation Slerp functions, so what is the difference between the two, observe the following examples:

The point where the yellow line and the red line intersect in         Figure 1 is the result of linear interpolation from point A to point B , and Figure 2 is the result of spherical interpolation , which may be called arc interpolation for easier understanding. The difference between the two can be clearly seen from the figure. From the perspective of quaternions, the rotation result obtained by linear interpolation for each frame is not uniform. Perform interpolation, such as the linear interpolation in Figure 1, the obtained quaternion is not a unit quaternion, so spherical interpolation is more reasonable because it does not change the length.

The test code is as follows:

using UnityEngine;
using UnityEditor;

/// <summary>
/// 线性插值
/// </summary>
public class LerpExample : MonoBehaviour
{
    [SerializeField] private Transform a; //点A
    [SerializeField] private Transform b; //点B

    private void OnDrawGizmos()
    {
        Handles.Label(transform.position, "O");
        Handles.Label(a.position, "A");
        Handles.Label(b.position, "B");

        Handles.color = Color.cyan;
        //以transform.position作为点O
        //绘制OA线段
        Handles.DrawLine(transform.position, a.position);
        //绘制OB线段
        Handles.DrawLine(transform.position, b.position);

        for (int i = 1; i < 10; i++)
        {
            //插值点
            Vector3 l = Vector3.Lerp(a.position, b.position, i * .1f);
            Handles.color = Color.red;
            //绘制点O到插值点的线段
            Handles.DrawLine(transform.position, l);
            Handles.color = Color.yellow;
            //绘制插值点之间的线段
            Handles.DrawLine(l, Vector3.Lerp(a.position, b.position, (i - 1) * .1f));
            Handles.Label(l, $"线性插值{i}");
        }
        Handles.DrawLine(b.position, Vector3.Lerp(a.position, b.position, .9f));
    }
}
using UnityEngine;
using UnityEditor;

/// <summary>
/// 球形插值
/// </summary>
public class SlerpExample : MonoBehaviour
{
    [SerializeField] private Transform a; //点A
    [SerializeField] private Transform b; //点B

    private void OnDrawGizmos()
    {
        Handles.Label(transform.position, "O");
        Handles.Label(a.position, "A");
        Handles.Label(b.position, "B");

        Handles.color = Color.cyan;
        //以transform.position作为点O
        //绘制OA线段
        Handles.DrawLine(transform.position, a.position);
        //绘制OB线段
        Handles.DrawLine(transform.position, b.position);

        for (int i = 1; i < 10; i++)
        {
            //插值点
            Vector3 l = Vector3.Slerp(a.position, b.position, i * .1f);
            Handles.color = Color.red;
            //绘制点O到插值点的线段
            Handles.DrawLine(transform.position, l);
            Handles.color = Color.yellow;
            //绘制插值点之间的线段
            Handles.DrawLine(l, Vector3.Slerp(a.position, b.position, (i - 1) * .1f));
            Handles.Label(l, $"球形插值{i}");
        }
        Handles.DrawLine(b.position, Vector3.Slerp(a.position, b.position, .9f));
    }
}

        When interpolating the Position coordinates and Rotation rotation in the Transform component, the interpolation function in Vector3 is usually used to process the Position, and the interpolation function in Quaternion is used to process the Rotation.

If we use the interpolation function in Vector3 to process Rotation, the following situation will occur:

code show as below:

using UnityEngine;
using System.Collections;

public class Example : MonoBehaviour
{
    [SerializeField] private Transform point1;
    [SerializeField] private Transform point2;

    private IEnumerator ExampleCoroutine(Transform target)
    {
        float beginTime = Time.time;
        Vector3 beginPosition = transform.position;
        Vector3 beginRotation = transform.eulerAngles;
        for (var duration = 2f; (Time.time - beginTime) < duration;)
        {
            float t = (Time.time - beginTime) / duration;
            transform.position = Vector3.Lerp(beginPosition, target.position, t);
            transform.eulerAngles = Vector3.Lerp(beginRotation, target.eulerAngles, t);
            yield return null;
        }
        transform.position = target.position;
        transform.eulerAngles = target.rotation.eulerAngles;
    }
    private void OnGUI()
    {
        if (GUILayout.Button("POINT1", GUILayout.Width(200f), GUILayout.Height(50f)))
        {
            StartCoroutine(ExampleCoroutine(point1));
        }
        if (GUILayout.Button("POINT2", GUILayout.Width(200f), GUILayout.Height(50f)))
        {
            StartCoroutine(ExampleCoroutine(point2));
        }
    }
}

Here is the result using Quaternion.Lerp:

code show as below:

using UnityEngine;
using System.Collections;

public class Example : MonoBehaviour
{
    [SerializeField] private Transform point1;
    [SerializeField] private Transform point2;

    private IEnumerator ExampleCoroutine(Transform target)
    {
        float beginTime = Time.time;
        Vector3 beginPosition = transform.position;
        Quaternion beginRotation = transform.rotation;
        for (var duration = 2f; (Time.time - beginTime) < duration;)
        {
            float t = (Time.time - beginTime) / duration;
            transform.position = Vector3.Lerp(beginPosition, target.position, t);
            transform.rotation = Quaternion.Lerp(beginRotation, target.rotation, t);
            yield return null;
        }
        transform.position = target.position;
        transform.rotation = target.rotation;
    }
    private void OnGUI()
    {
        if (GUILayout.Button("POINT1", GUILayout.Width(200f), GUILayout.Height(50f)))
        {
            StartCoroutine(ExampleCoroutine(point1));
        }
        if (GUILayout.Button("POINT2", GUILayout.Width(200f), GUILayout.Height(50f)))
        {
            StartCoroutine(ExampleCoroutine(point2));
        }
    }
}

  Welcome to the public account "Contemporary Wild Programmer"

Guess you like

Origin blog.csdn.net/qq_42139931/article/details/123281928