Unity—Lerp插值函数

时间:2022-06-27 04:16:35

转载自CSDN游一法师

有时,我们在做游戏时会发现有些跟随动作不够圆滑或者需要一个缓冲的效果,这时,一般会考虑到插值。所以对插值的理解是必需的。(比如摄像机跟随主角)

插值是数学上的一个概念,在这里用公式表示就是:from + (to - from) * t;这也就是Lerp的返回值(用这个公式分别算出x,y,z)。

static function Lerp (from : Vector3, to : Vector3, t : float) : Vector3 

from 是起始的位置,to是目标位置,按照数字t在from到to之间插值。

按照分数t在from到to之间插值。这是最常用的寻找一点沿一条线的两个端点之间一些分数的方式(例如,在那些点之间逐渐移动一个对象)。这分数是在范围[ 0…1]。t是夹在 [0…1]之间,当t = 0时,返回from,当t = 1时,返回to。当t = 0.5 返回from和to的中间点。

这句话比较难理解,下面举个例子。

Unity—Lerp插值函数       Unity—Lerp插值函数

这和我们用公式算出来的如出一辙。现在我们再看一个具体的例子

//在1秒时间动画位置移动从from开始到to结束。(这是官方的例子)

Unity—Lerp插值函数

Unity—Lerp插值函数

位置移动从start开始到end结束,这好理解,但是为什么是1秒呢?

Time.time是从0开始随时间增加的。

例1的t是一个固定的值,返回一个固定的向量。此时t是变量,在不断增加。那么:

当Time.time = 0时--->transform.position = start.position,位置没有变化;

当Time.time从0趋向于1时--->transform.position 不断接近start.position,该脚本是挂在start物体上的,所以start会不断靠近end。

那么问题来了,当Time.time>1的时候,会怎么样呢?额(⊙o⊙)…我们说不会。

由上面的公式from + (to - from) * t可知,当t=1时,to - from = 0,此时t就无效了。

例1是从静态角度看,例2是从动态角度看的(两个变量,一个是时间在变化,一个是位置在变化)。

想一想例2,如果不是Time.time,而是0.5,会怎么样?(只看一个变量)

-----这里的start.position如果是个初始定值,那么明显只会移动到一半出,如果换成transform.position,才会如下图速度逐渐减小的缓冲至终点;

Unity—Lerp插值函数

由图易知:A物体会不断以0.5的比例无限接近于B----In fact,由于数据是有限位数的(如float),Unity中是可以取得B点位置的

如果上面都理解了,那么看官方的第二个例子就没什么问题了,试一试吧!

//像弹簧一样跟随目标物体

public class testlerp : MonoBehaviour {
    private Vector3 des = new Vector3(-16, 1, 1);
    Vector3 start = new Vector3(1, 1, 1), end = new Vector3(2, 2, 2);
    Vector3 result;
    Vector3 start1;
    // Use this for initialization
    void Start () {
        start1 = this.transform.position;
    }
    
    // Update is called once per frame
    void Update () {
        result = Vector3.Lerp(start,end,0.5f);
        Debug.Log($"{result}");

        //transform.position = Vector3.Lerp(start1,des,0.5f);
        transform.position = Vector3.Lerp(transform.position, des, Time.fixedDeltaTime*5);
    }
}

 

此时官网的案列,以速度speed匀速走完全程:放在FixedUpdate()中最好

using UnityEngine;
using System.Collections;
 
public class ExampleClass : MonoBehaviour {
    public Transform startMarker;
    public Transform endMarker;
    public float speed = 1.0F;
    private float startTime;
    private float journeyLength;
    public Transform target;
    public float smooth = 5.0F;
    void Start() {
        startTime = Time.time;
        journeyLength = Vector3.Distance(startMarker.position, endMarker.position);
    }
    void Update() {
        float distCovered = (Time.time - startTime) * speed;
        float fracJourney = distCovered / journeyLength;
        transform.position = Vector3.Lerp(startMarker.position, endMarker.position, fracJourney);
    }
}