Unity動畫關鍵幀插值

Unity動畫的關鍵幀插值有2種模式1,一種是3次多項式插值,另一種是3次貝塞爾曲線插值。下面介紹具體實現,首先我們先看關鍵幀的幾個重要成員定義:

inTangent,左側的斜率,下面用it來表示
inWeight,決定貝塞爾曲線的第2個點的x,用iw表示
outTangent,右側的斜率,用ot表示
outWeight,決定貝塞爾曲線第3個點的x,用ow表示
value,關鍵幀的值,用y表示
time,關鍵幀的時間,用x表示

給定兩個關鍵幀,

Fi={iti,iwi,oti,owi,xi,yi}, 0i1 F_i = \{ it_i, iw_i, ot_i, ow_i, x_i, y_i \},\ 0 \le i \le 1

三次多項式插值

三次多項式插值在兩個關鍵幀的weightedMode都是None時使用。

三次多項式方程爲

y=f(x)=ax3+bx2+cx+d y = f(x) = ax^3+bx^2+cx+d

我們可以使用如下4個方程解得4個係數

{f(x0)=y0f(x1)=y1f(x0)=ot0f(x1)=it1 \begin{cases} f(x_0) = y_0 & \\ f(x_1) = y_1 & \\ f'(x_0) = ot_0 & \\ f'(x_1) = it_1 \end{cases}

得到的結果以矩陣表示爲

[abcd]=[x03x02x01x13x12x113x022x0103x122x110]1[y0y1ot0it1] \begin{bmatrix} a \\ b \\c \\d \end{bmatrix} = \begin{bmatrix} x_0^3 & x_0^2 & x_0 & 1 \\ x_1^3 & x_1^2 & x_1 & 1 \\ 3x_0^2 & 2x_0 & 1 & 0 \\ 3x_1^2 & 2x_1 & 1 & 0 \end{bmatrix}^{-1} \begin{bmatrix} y_0 \\ y_1 \\ ot_0 \\ it_1 \end{bmatrix}

計算逆矩陣比較麻煩,我們可以將曲線的區間平移並規格化到[0,1][0,1]中再做計算,這樣就方便許多,新的方程組爲

{f(0)=y0f(1)=y1f(0)=ot0(x1x0)f(1)=it1(x1x0) \begin{cases} f(0) = y_0 & \\ f(1) = y_1 & \\ f'(0) = ot_0 (x_1 - x_0) & \\ f'(1) = it_1 (x_1 - x_0) \end{cases}
注意,由於進行了縮放,端點處的斜率也需要進行縮放。
解得
[abcd]=[(ot0+it1)(x1x0)2(y1y0)(2ot0it1)(x1x0)+3(y1y0)ot0(x1x0)y0] \begin{bmatrix} a \\ b \\c \\d \end{bmatrix} = \begin{bmatrix} (ot_0+it_1)(x_1-x_0)-2(y_1-y_0) \\ (-2ot_0-it_1) (x_1 - x_0) + 3(y_1-y_0) \\ ot_0(x_1-x_0) \\ y_0 \end{bmatrix}

給定時間tt,我們可以使用如下公式得到插值的結果

f(tx0x1x0) f(\frac{t-x_0}{x_1-x_0})

我們驗證一下結果,給定兩個關鍵幀2

F0={0,13,0,13,0,0}F1={0,13,0,13,1,1} F_0 = \{0,\frac{1}{3},0,\frac{1}{3},0,0\} \\ F_1 = \{0,\frac{1}{3},0,\frac{1}{3},1,1\}

該多項式實際爲

y=2x3+3x2 y=-2x^3+3x^2

對glsl熟悉的朋友應該會對這個多項式不陌生,就是smoothstep所用hermite多項式。

unity中的曲線爲
hermite polynomial
在unity中查看1/31/32/32/3處的結果爲
values in editor
我們再看一下代入多項式後的值

f(13)=727=0.2592592593f(23)=2027=0.7407407407 f(\frac{1}{3}) = \frac{7}{27} = 0.2592592593 \\ f(\frac{2}{3}) = \frac{20}{27} = 0.7407407407

結果是一致的。

貝塞爾曲線插值

多項式插值不使用inWeightoutWeight,根據unity文檔

Sets the incoming weight for this key. The incoming weight affects the slope of the curve from the previous key to this key.

第一想法是使用了貝塞爾曲線一類的插值方法。

三次貝塞爾曲線需要4個點,而這裏4個點的定義如下

P0=(x0,y0)P1=(x0+ow0(x1x0),y0+ow0ot0(x1x0)P2=(x1iw1(x1x0),y1iw1it1(x1x0)P3=(x1,y1) \begin{aligned} P_0 &= (x_0,y_0) \\ P_1 &= (x_0 + ow_0(x_1-x_0),y_0+ow_0\cdot ot_0 (x_1-x_0) \\ P_2 &= (x_1 - iw_1(x1-x_0),y_1-iw_1\cdot it_1 (x_1 - x_0) \\ P_3 &= (x_1,y_1) \end{aligned}

這裏iwiwowow用來決定中間點的xx座標,且權重在[0,1][0,1]內。

我們來驗證一下,給定如下兩個關鍵幀(我們需要將Tangent設置爲Weighted)

F0={0,13,1,1,0,0}F1={0,13,0.5,0.5,1,1} \begin{aligned} F_0 &= \{0,\frac{1}{3},-1,1,0,0\} \\ F_1 &= \{0,\frac{1}{3},-0.5,0.5,1,1\} \end{aligned}

unity中的曲線爲
bezier curve

在unity中查看1/31/32/32/3處的結果爲

bezier values in editor
由於貝塞爾曲線不是以xx爲參數的曲線,我們需要先解得對應參數tt,之後再代入得到yy。三次方程有封閉解,具體見Wikipedia

解得對應的兩個tt以及yy

t0=0.1371916262y0=0.2429122496t1=0.4502223408y1=0.1009137022 \begin{aligned} t_0 &= 0.1371916262 \\ y_0 &=-0.2429122496 \\ t_1 &= 0.4502223408\\ y_1 &= 0.1009137022 \end{aligned}

可以看到與editor中的結果一致。

默認權重

當一個關鍵幀的weightedMode不是weighted時,此時會默認採用1/31/3作爲權重,該權重爲unity默認寫入的值,通過觀察clip文件可知。


  1. 官方文檔沒有給出具體算法,貝塞爾曲線插值只是猜測。 ↩︎

  2. 其中的權重13\frac{1}{3}會在貝塞爾曲線插值中講到 ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章