一、Unity插值函數Lerp()
通過官方文檔簡單了解插值函數(https://docs.unity3d.com/ScriptReference/index.html),可以看到插值函數有很多
Mathf.Lerp()
從最簡單的數學插值來看,插值函數接收三個參數a,b,t,在ab之間,以t作為比例來插值。
例如,Lerp(0, 10, 0.4f),此時返回4,即 a + (b - a) * t
注意,第三個參數要小於1,如果大於1,則還是返回b。
其他的插值也類似於此,只不過插值的對象變為向量,顏色等等。
二、增量時間Time.deltatime
游戲都是一幀一幀顯示的,平時說的60FPS就是1秒60幀;幀率越高,游戲運行就越流暢。
增量時間deltatime,就是從上一幀到現在所經過的時間。如果游戲穩定在60FPS,那么增量時間就是1/60s,當然實際游戲運行幀數肯定在不斷變化,所以Time.delta的值也在不斷地變化。簡單來說,Time.deltatime就是運行每一幀所花的時間。
三、插值函數的作用
在看官方文檔以及其他的代碼時,經常發現插值函數的第三個參數往往和增量時間有關,如:
using UnityEngine; public class Example : MonoBehaviour { Transform target; float speed = 0.1f; void Update() { transform.position = Vector3.Lerp(transform.positon, target.position, Time.deltatime * speed); } }
那么為什么線性插值的第三個參數要用到增量時間呢?
首先,需要理解為什么要利用插值函數。
不妨想象以下游戲場景,在主人身后有一只寵物,它會時刻跟在主人身后,如果主人走遠了,它也會快速跟上。
可以發現兩點,第一,寵物不是瞬間移動到主人身后的,而是一點一點走過來的,第二,寵物和主人離得越遠,寵物跟隨的速度就越快,離主人越近,寵物的速度就越慢,而Lerp()函數就可以實現彈性跟隨的效果。
transform.position = Vector3.Lerp(transform.positon, target.position, Time.deltatime * speed);
這行代碼中,Lerp()函數返回一個自身位置和target位置之間的一個位置,比例是Time.deltatime * speed,然后再把這個值作為自己的新位置
如果第三個參數是0.5,自身位置為0,目標位置為10,那么第一次自身從0移動到5,第二次從5移動到7.5,即每次都會移動(目標位置 - 自身位置)* 0.5的位置,由於自己越來越接近目標位置,這個值也會越來越小,所以每次往前移動的距離也就越來越小,這樣就實現了彈性的效果。
當然,從數學的角度來看,只能無限接近目標位置,永遠也到達不了目標位置,但是玩家是感覺不出這一點的差距的。
四、使用增量時間進行插值
最后回到本篇的重點,為什么在插值函數中要使用增量時間作為參數呢?
還是以最簡單的數學插值為例
a = Mathf.Lerp(a, b, 0.1f);
每次運行后,a都會以10%的速度向b靠近。假設a和b之間相差1個單位,第一幀后,a和b之間剩余的距離變為0.9,第二幀過后,a和b之間剩余的距離變為0.81 = 0.9 * 0.9。以此類推,第n幀過后,a和b之間的剩余距離變為0.9^n
如果FPS=10,那么一秒后a和b之間的剩余距離變為0.9^10,如果如果FPS=20,那么一秒后a和b之間的剩余距離變為0.9^20,也就是說插值效果和電腦運行的幀率有關。
下面考慮使用增量時間的情況(一般會用speed來乘以增量時間,這里為了簡化就假設speed為1)
a = Mathf.Lerp(a, b, Time.deltatime);
類似的,在n幀過后,a和b之間的剩余距離變為 (1 - Time.deltatime) ^ n,如果假設電腦幀率穩定的話,根據增量時間的定義,Time.deltatime表示每幀運行的事件,即Time.deltatime= 1/n
那么,a和b之間的剩余距離變為 (1 - 1/n) ^ n。可以看出,插值效果仍然和幀率有關,但是如果帶入數字詳細計算的話,會發現實際差距已經很小。
例如,n = 30,即FPS=30,那么結果大致是0.36166,如果 n = 60,結果大致是0.36479
這種寫法比較簡便,而且不同幀率下的插值效果相差很小,這也是為什么大部分代碼都會這么寫的原因。
最后,給出如下寫法:
a = Mathf.Lerp(a, b, 1 - speed ^ Time.deltatime);
通過同樣的計算可得,a和b之間的剩余距離變為 [1 - (1 - speed ^ (1/n) ] ^ n = speed,這種寫法做到了完全和幀率無關,即無論在哪一台電腦上運行,在相同的時間后都會有相同的插值效果
五、總結
在不苛求完美的情況下,一般采取第二種寫法,就可以取得較好的插值效果效果
參考文章:https://www.construct.net/en/blogs/ashleys-blog-2/using-lerp-delta-time-924