Sprite Animation? 序列幀動(dòng)畫
自由度(degrees of freedom,DoF)對(duì)于剛體而言描述它的運(yùn)動(dòng)需要3個(gè)位移3個(gè)旋轉(zhuǎn),一共6個(gè)自由度
頂點(diǎn)動(dòng)畫(per-vertex animation)利用網(wǎng)格的頂點(diǎn)來控制運(yùn)動(dòng)。此時(shí)網(wǎng)格上的每個(gè)頂點(diǎn)有具有3個(gè)平移自由度,通過對(duì)網(wǎng)格頂點(diǎn)坐標(biāo)的變換就可以實(shí)現(xiàn)模型的運(yùn)動(dòng)。這種動(dòng)畫方法在人物角色上的應(yīng)用比較少,但在物理仿真中則相對(duì)比較常見。
Skinned Animation 蒙皮動(dòng)畫
通過控制角色內(nèi)部骨骼的運(yùn)動(dòng)來實(shí)現(xiàn)整個(gè)角色的運(yùn)動(dòng)。和剛體動(dòng)畫相比,蒙皮動(dòng)畫可以實(shí)現(xiàn)更加真實(shí)和自然的運(yùn)動(dòng)效果。
Physics-based Animation 物理動(dòng)畫
物理動(dòng)畫是完全基于物理法則的動(dòng)畫模擬方法,和蒙皮動(dòng)畫相比需要更加深入的數(shù)學(xué)物理知識(shí)進(jìn)行描述。
接下來我們介紹蒙皮動(dòng)畫的實(shí)現(xiàn)細(xì)節(jié)。從整體上來看,蒙皮動(dòng)畫的實(shí)現(xiàn)包括以下5個(gè)步驟:
- 建立網(wǎng)格模型;
- 建立網(wǎng)格模型附著的骨骼;
- 為網(wǎng)格上每個(gè)頂點(diǎn)賦予骨骼對(duì)應(yīng)的權(quán)重;
- 利用骨骼完成角色的運(yùn)動(dòng);
- 結(jié)合頂點(diǎn)的骨骼權(quán)重實(shí)現(xiàn)網(wǎng)格的運(yùn)動(dòng)。
上述步驟看上去不是很難,但在實(shí)際編程中需要多加小心防止出現(xiàn)網(wǎng)格爆炸的問題。
Different Spaces
要描述骨骼的運(yùn)動(dòng)我們還需要引入相應(yīng)的坐標(biāo)系統(tǒng)。首先整個(gè)游戲世界定義了一個(gè)世界坐標(biāo)系(world space),所有的物體都位于這個(gè)坐標(biāo)系中;對(duì)于每個(gè)單獨(dú)的模型,模型自身還定義了一個(gè)模型坐標(biāo)系(model space);最后每個(gè)骨骼還定義了一個(gè)局部坐標(biāo)系(local space)來描述網(wǎng)格頂點(diǎn)和骨骼的相對(duì)位置關(guān)系。任意兩個(gè)坐標(biāo)系之間的變換關(guān)系可以通過3個(gè)平移和3個(gè)旋轉(zhuǎn)一共6個(gè)自由度來表示,這樣每個(gè)頂點(diǎn)的坐標(biāo)都可以從局部坐標(biāo)系變換到模型坐標(biāo)系再變換到世界坐標(biāo)系上。
Joint
我們定義骨骼與骨骼之間相連接的部位為一個(gè)關(guān)節(jié)(joint)。實(shí)際上我們不會(huì)直接按照骨骼進(jìn)行編程,而是利用關(guān)節(jié)及他們直接的連接關(guān)系來表達(dá)整個(gè)骨骼的運(yùn)動(dòng)。
在游戲建模中除了常見的四肢外可能還會(huì)根據(jù)角色的服裝和特點(diǎn)來構(gòu)建更加復(fù)雜的骨骼模型。比如說玩家手中的武器就是通過在角色手上綁定一個(gè)新的骨骼來實(shí)現(xiàn)的。
除此之外,在進(jìn)行建模時(shí)我們往往還會(huì)定義一個(gè)root關(guān)節(jié)。不同于前面介紹過的胯部骨骼,root關(guān)節(jié)一般會(huì)定義在角色的兩腳之間,這樣方便把角色固定的地面上。類似地,對(duì)于坐騎的骨骼也往往會(huì)單獨(dú)把root關(guān)節(jié)定義在接近地面的位置。
很多游戲動(dòng)畫需要將不同的骨骼綁定到一起。最直觀的例子就是角色騎馬的動(dòng)畫,此時(shí)角色和馬都有自身獨(dú)立的動(dòng)畫而我們需要將它們組合到一起完成角色騎馬的動(dòng)作。要實(shí)現(xiàn)這種功能需要設(shè)計(jì)一個(gè)單獨(dú)的mount關(guān)節(jié),然后通過這個(gè)關(guān)節(jié)將兩個(gè)模型拼接到一起。需要注意的是在拼接時(shí)不僅要考慮關(guān)節(jié)坐標(biāo)的一致性,更要保證兩個(gè)模型的mount關(guān)節(jié)上有一致的朝向,(不僅是接觸點(diǎn)的重合,更是坐標(biāo)軸的完全重合)這樣才能實(shí)現(xiàn)模型正確的結(jié)合。
歐拉角
Euler Angle
三維空間中的旋轉(zhuǎn)要更復(fù)雜一些。我們可以把任意三維空間的旋轉(zhuǎn)分解為繞三個(gè)軸的旋轉(zhuǎn),每個(gè)旋轉(zhuǎn)都對(duì)應(yīng)一個(gè)三維旋轉(zhuǎn)矩陣,這樣就可以通過繞三個(gè)軸的旋轉(zhuǎn)角度來進(jìn)行表達(dá)。這種描述三維旋轉(zhuǎn)的方法稱為歐拉角(Euler angle)。
歐拉角的主要缺陷如下:
- 萬(wàn)向鎖及相應(yīng)的自由度退化問題;
- 很難對(duì)歐拉角進(jìn)行插值;
- 很難通過歐拉角對(duì)旋轉(zhuǎn)進(jìn)行疊加;
- 很難描述繞$x, y, z$軸之外其它軸的旋轉(zhuǎn)。
由于這些缺陷的存在,游戲引擎中幾乎不會(huì)直接使用歐拉角來表達(dá)物體的旋轉(zhuǎn)。
Joint Pose
有了三維旋轉(zhuǎn)的表達(dá)方法后我們就可以利用關(guān)節(jié)的姿態(tài)來控制角色模型的運(yùn)動(dòng)。具體來說,我們每個(gè)關(guān)節(jié)的姿態(tài)可以分為平移、旋轉(zhuǎn)和縮放三個(gè)部分,把它們組合到一起就可以通過一個(gè)仿射矩陣(affine matrix)來描述關(guān)節(jié)的姿態(tài)。
對(duì)于骨骼上的每一個(gè)關(guān)節(jié),我們實(shí)際上只需要存儲(chǔ)它相對(duì)于父節(jié)點(diǎn)的相對(duì)姿態(tài)。這樣在計(jì)算絕對(duì)姿態(tài)時(shí)可以利用仿射矩陣的傳遞性從根節(jié)點(diǎn)出發(fā)進(jìn)行累乘即可。
這種利用相對(duì)坐標(biāo)系來描述位姿關(guān)系的好處在于它可以正確地對(duì)角色動(dòng)作進(jìn)行插值,而如果直接從絕對(duì)坐標(biāo)系進(jìn)行插值則會(huì)得到錯(cuò)誤的結(jié)果。
Skinning Matrix
在前面我們介紹過模型的每個(gè)頂點(diǎn)是附著在骨骼上的,因此在關(guān)節(jié)姿態(tài)發(fā)生變化后頂點(diǎn)會(huì)跟著關(guān)節(jié)一起運(yùn)動(dòng)。
記頂點(diǎn)$V$在關(guān)節(jié)$J$定義的局部坐標(biāo)系下的坐標(biāo)為$V_b^l$,初始時(shí)刻進(jìn)行綁定時(shí)$V$在模型坐標(biāo)系下的坐標(biāo)為$V_b^m$。在$t$時(shí)刻,當(dāng)關(guān)節(jié)位姿發(fā)生變化后頂點(diǎn)的局部坐標(biāo)保持不變。此時(shí)頂點(diǎn)在模型坐標(biāo)系下的坐標(biāo)和局部坐標(biāo)直接滿足變換關(guān)系:
其中$M_{b(J)}^m$即為初始時(shí)刻進(jìn)行綁定時(shí)關(guān)節(jié)$J$對(duì)應(yīng)的姿態(tài)。
利用$t$時(shí)刻關(guān)節(jié)的位姿$M_J^m(t)$,可以得到頂點(diǎn)$V$模型坐標(biāo)系下的坐標(biāo)$V^m(t)$與初始時(shí)刻模型坐標(biāo)系下綁定的坐標(biāo)$V_b^m$之間的變換關(guān)系:
其中$K_J = M_J^m(t) \cdot (M_{b(J)}^m)^{-1}$稱為關(guān)節(jié)$J$的蒙皮矩陣(skinning matrix)。
對(duì)于同一個(gè)頂點(diǎn)綁定到多個(gè)骨骼的情況則需要通過插值進(jìn)行處理。此時(shí)頂點(diǎn)V會(huì)同時(shí)存儲(chǔ)它所綁定到的關(guān)節(jié)以及對(duì)應(yīng)的權(quán)重,其在世界坐標(biāo)系下的坐標(biāo)為它在每個(gè)關(guān)節(jié)上定義的局部坐標(biāo)轉(zhuǎn)換到世界坐標(biāo)后的加權(quán)和。
Interpolation
在動(dòng)畫制作過程中一般只會(huì)記錄下一系列關(guān)鍵幀上骨骼的姿態(tài),而要得到實(shí)際的動(dòng)畫還需要通過插值來獲得中間幀上模型的運(yùn)動(dòng)。
線性插值是最基本的插值方法,我們可以通過對(duì)關(guān)節(jié)姿態(tài)的插值來計(jì)算中間幀上的模型運(yùn)動(dòng)。
對(duì)于三維旋轉(zhuǎn)的插值要相對(duì)復(fù)雜一些,不過我們可以借助四元數(shù)的運(yùn)算來進(jìn)行處理。要獲得插值后的旋轉(zhuǎn)只需要對(duì)四元數(shù)直接進(jìn)行線性插值,然后再進(jìn)行歸一化即可,這樣的方法稱為NLERP。
需要說明的是NLERP并不是真的對(duì)旋轉(zhuǎn)進(jìn)行線性插值。當(dāng)動(dòng)畫的幀數(shù)較高時(shí)NLERP會(huì)有明顯的違和感,這是由于它沒有考慮旋轉(zhuǎn)并不是線性空間。從角度上來看插值是不均勻的
想要真的對(duì)旋轉(zhuǎn)進(jìn)行線性插值可以使用SLERP這樣的算法,不過SLERP的計(jì)算代價(jià)要比NLERP要大一些。
AnimationRuntime Pipeline
我們把上面介紹過的算法整理一下就得到了一個(gè)簡(jiǎn)單的蒙皮動(dòng)畫管線如下。現(xiàn)代3A游戲在此基礎(chǔ)上還會(huì)更多地把計(jì)算配置到GPU上來充分計(jì)算資源。
另行學(xué)習(xí):IK,動(dòng)畫混合,給Player安裝武器文章來源:http://www.zghlxwxcb.cn/news/detail-856037.html
參考文章:GAMES104課程筆記08-Basics of Animation Technology - Bo's Blog (peng00bo00.github.io)文章來源地址http://www.zghlxwxcb.cn/news/detail-856037.html
到了這里,關(guān)于Games104 現(xiàn)代游戲引擎3的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!