很多DCC工具都提供了Curves Editor,通過控制點來構(gòu)造插值曲線,這樣可以精確地插值軌跡。在我們游戲的過場編輯器中,我們并沒有開發(fā)這類工具,一方面由于時間人力有限,另一方面希望能夠提供一種直觀簡便的方式達(dá)到想要的效果。因此我們支持兩種攝像機路徑創(chuàng)建方法:1)以攝像機視角直接將攝像機擺到想要位置,保存此時攝像機的位置與旋轉(zhuǎn);2)將3DS Max中的路徑導(dǎo)出為游戲的過場格式。前者可以滿足90%的過場編輯需求,后者滿足了10%的復(fù)雜路徑編輯需求。
不管使用那種方式,都需要將離散點進(jìn)行插值(interpolation)以便得到平滑路徑。這里就牽涉到位置插值和朝向插值。
從插值函數(shù)上可分為三類:1)線性;2)多項式;3)樣條。顧名思義,線性插值采用線性函數(shù),多項式插值采用多項式,而樣條插值則采用了一組多項式組成的分段函數(shù)。由于攝像機的關(guān)鍵路徑點通常都會大于2個,所以插值方法上就必須選取樣條方法。
一、位置插值
1.1 樣條類型選擇
在這里我們僅考慮三次樣條插值,因為它們可達(dá)到C2連續(xù)。三次樣條中主要以Bezier、Catmull-Rom、均勻B樣條為考查對象,它們都具有計算開銷小的優(yōu)點。可以通過下面公式來定義它們:
簡化為:
下面表格列出了三種插值曲線對應(yīng)的G和M:
如下圖所示,對4個點進(jìn)行Bezier插值得到的曲線只會有兩個點被曲線穿過,而B-Spline插值得到的曲線不會經(jīng)過控制點,只有Catmull-Rom Spline可以得到穿過除起點和終點之間的所有控制點。正因為Catmull-Rom具有這個特性,使得它被廣泛地應(yīng)用在關(guān)鍵幀平滑插值上,因此我們選擇了Catmull-Rom樣條作為攝像機位置點的插值算法。
1.2 實現(xiàn)
參考:
[1] Mathematics for 3D Game Programming and Computer Graphics 3e by Eric Lengyel
[2] http://en.wikipedia.org/wiki/Catmull-Rom_spline#Catmull.E2.80.93Rom_spline
[3] http://www.codeproject.com/Articles/30838/Overhauser-Catmull-Rom-Splines-for-Camera-Animatio
二、朝向(旋轉(zhuǎn))插值
2.1 Euler Angles VS Quaternion
三維空間中描述旋轉(zhuǎn)的主要方法有Euler Angles和Quaternion。Euler Angles有三個明顯的問題:1)三軸上的旋轉(zhuǎn)順序敏感;2)Gimbal Lock現(xiàn)象導(dǎo)致旋轉(zhuǎn)自由度丟失;3)獨立地對三個旋轉(zhuǎn)分量進(jìn)行插值,忽略了三軸之間的依賴關(guān)系,導(dǎo)致插值結(jié)果不理想。與Euler Angles不同的是,Quaternion沒有將旋轉(zhuǎn)分解到三個軸向上,而是用一個旋轉(zhuǎn)軸和繞該軸的旋轉(zhuǎn)角度來描述,所以從根本上消除了Euler Angles的三大問題。有關(guān)Quaternion的詳細(xì)描述可參考[1],在此不再累述。
2.2 LERP VS SLERP
四元數(shù)線性插值(Linear Quaternion interpolation)的計算公式為:
四元數(shù)球面線性插值(Spherical Linear Quaternion interpolation)的計算公式為:
其中,θ為兩個四元數(shù)的夾角。
為了方便展示,我們考慮在2D情況對角度V進(jìn)行兩次插值,兩種算法在插值效果上存在的差異,如下圖(b為LERP、c為SLERP):
從圖中可以看出LERP其實是對兩四元數(shù)在圓上的弦進(jìn)行了等分,而SLERP則是對圓弧進(jìn)行等分。由此得出的結(jié)論是,SLERP得到了比LERP更平滑的插值結(jié)果。
為了保證插值曲線的C2連續(xù)性,需要使用球面四邊形插值(Spherical Quadrangle interpolation)方法。例如,對q1和q2插值,首先要用q0、q1、q2、q3計算出兩個控制點(Inner Quadrangle Point),公式如下:
然后通過下式得到最終插值結(jié)果:
2.3 實現(xiàn)
上面代碼沒有考慮兩個四元數(shù)之間夾角大于180°的情況。例如,考慮q1->q2的插值角度θ>180°,我們可以讓q1->q2反向旋轉(zhuǎn)2π-θ,即旋轉(zhuǎn)-(2π-θ),根據(jù)四元數(shù)的定義[v*sin(θ/2) , cos(θ/2)],那么對q2進(jìn)行處理變?yōu)閇-v*sin(θ/2) , -cos(θ/2)]。這個處理可以放在AddSplinePoint中來做:
參考:
[1] Quaternions, Interpolation and Animation by EB Dam - 1998
[2] Game Engine Architecture by Jason Gregory - 2009
[3] https://theory.org/software/qfa/writeup/node12.html