1. 程式人生 > 其它 >Unity 通過Lerp實現勻速平滑插值效果

Unity 通過Lerp實現勻速平滑插值效果

很多時候在Unity的一些場景中中會用到平滑插值。比如我有一個Animator狀態樹,動畫通過一個float數值來控制。但是數值是瞬間變化的,動畫如果也是瞬間切換,沒有過渡效果的話,看著就會很生硬。所以就需要對float進行線性平滑插值。

Mathf.Lerp

Unity官方是有線性平滑插值的函式的,即Lerp函式

Unity中有很多資料都可以通過Lerp來進行線性平滑插值,不過我這次只打算說一下Mathf.Lerp。
其實所有Lerp函式都大差不差,先來看Mathf.Lerp的函式

public static float Lerp(float a, float b, float t);

Mathf.Lerp由三個引數構成,函式最終會返回一個float浮點數,大小是a與b之間關於t的浮點插值結果。t不要大於1,因為t被限制在了0-1之間。
但其實原理很簡單

t = 0, return a
t = 0.5, return (a + b) / 2
t = 1, return b

所以當給定了目標數值a,最終結果b後,Lerp函式會根據當前t的大小來返回一個浮點數。所以,如果我們想要實現一個平均且勻速的線性平滑插值,那我們必須保證t是以一個平均的速度從0開始增長到1的。
t更像是一個百分比數(比如,當t = 0.5時,就相當於長度的一半,如果a = 0,b = 5,則相當於長度5的一半,返回2.5),ab之間的長度通過這個百分比數找到一個點,然後將這個點的數值返回。

Unity中的使用

眾所周知,Unity生命週期中有兩個比較重要的函式,分別是Update和FixedUpdate

Update是每幀便執行一次,FixedUpdate則是有一個固定的數值(一般是0.02s,可以修改),每隔固定的時間執行一次。

先從容易理解的FixedUpdate來說,可以理解為0.02s執行一次。因為是固定速率執行,所以相應的時間增量Time.fixedDeltaTime就等於0.02。
而勻速平滑插值就要保證t是勻速增長的,所以給定一個變數,然後每次FixedUpdate去增加0.02直至等於我們想要的時間,比如1s。最後將這個變數與我們想要時間做一個比值,就可以當成勻速變化的t來用了。

下面是程式碼(FixedUpdate模式)

public float fixedTime = 0.0f;

private float target = 5.0f;
private float fixedDeltaTime = 0.0f;

private void FixedUpdate()
{
    fixedTime = Mathf.Lerp(fixedTime, target, Time.fixedDeltaTime / (target - fixedDeltaTime));
    fixedDeltaTime += Time.fixedDeltaTime;
    Debug.Log(string.Format("currentTime:{0}", fixedTime));
}

需要注意的是,數值變化的過程中,“距離”target應該是越來越近的,所以後面的速度應該是,目標時間減去已經經過的時間,然後用時間增量deltaTime去做比值。結果就是當前時間增量中應該變化的數值佔總數值的比率。
Update同理,只需要把Time.fixedDeltaTime換成Time.deltaTime就可以了
最後Log證明一下確實是勻速運動的

從44秒到45秒正好過了1.0