骨骼動畫原理及簡單實現
骨骼動畫的含義,一句話,骨骼的朝向和位置,影響頂點的位置。
骨骼動畫的計算方法,一句話,頂點在骨骼空間裡的座標,不受骨骼本身變化影響。
因此,我們只要先將頂點從模型空間變換到骨骼空間,在骨骼發生旋轉位移後,再把骨骼空間的座標變換回模型空間即可。
這方面的詳細介紹已經有很多了,這裡推薦
這個嚮導從骨骼動畫的原理,資料檔案格式分析解析到實際繪製,都有比較清晰的說明。
這裡還有一個翻譯後的版本
這篇教程裡詳細解釋的內容,我這裡就不重複了。下面介紹一些我照著文章一步步實現時碰到的問題。
1.關於bind pose的解釋
不得不說,遊戲界的術語有時還真是混亂。在《Game Engine Architecture》一書中,作者提到bind pose是指假設不考慮骨骼,直接渲染出來的模型形狀(一般來講是個兩臂平身直立的造型,也被稱為T-pose)。而在上面的嚮導裡,同樣的概念被稱為modeling pose,而bind pose則是骨骼導致模型變化後的形狀。不過從使用的collada dae檔案裡來看,頂點到骨骼空間的變換被稱為INV_BIND_MATRIX,似乎還是《Game Engine Architecture》裡的說法更靠譜一點。以下我所使用的bind pose,也特指書中的概念。
2.bind pose下骨骼的位置
想畫出bind pose下joint的預設位置,但是發現collada dae檔案裡並沒有直接提供這個矩陣。後來想到,既然INV_BIND_MATRIX可以將頂點從世界空間變換到joint空間,那麼它的逆矩陣就是我這時需要的了。
3.joint矩陣的含義
joint矩陣是joint節點到父節點的空間轉換矩陣。一般來說,每個joint在每一幀裡都要提供一個變換矩陣。要注意在collada裡,這個矩陣並不是相對於bind pose裡joint的變化,不需要再乘以bind pose的joint矩陣。另外,在collada裡,還有可能出現某個joint有個非joint型別的xml節點,節點裡也有變換矩陣。要想得到正確的顯示結果,父xml節點的這個變換矩陣是需要乘的。collada文件裡特意指出,變換是從物件空間到物件空間,而不是從物件空間到世界空間,也許就特指這點吧。
4.collada的問題
對3d製作不熟悉,不知道對於模型資料,有沒有bmp、png這種標準格式。從教程以及網上的一些資料來看,collada格式似乎是朝著這個方向發展的,起碼3ds max,maya,blend都可以匯出collada檔案。但是從使用情況來看,我覺得對於初學者,這種格式似乎不是一個很好的選擇。似乎為了相容各個3d製作軟體,格式設計的非常複雜。例如骨骼動畫的資料,就分散在<library_geometries>、<library_controllers>、<library_visual_scenes>、<library_animations>幾個xml節點裡。而且不同的3d製作軟體,匯出的collada在資料表現格式上還是稍有區別的。例如同樣的空間變換,blender匯出的可能是一個矩陣,maya匯出的可能是<rotate>、<translate>幾個節點,給解析帶來了不少麻煩。官方雖然提供了dom庫和viewer,但是維護似乎有問題,最新版本甚至都無法編譯成功。下面我列舉幾個使用教程的collada轉換工具和解析程式碼時遇到的一些問題。
A.三角化
如果使用自己生成的collada檔案,可能頂點資料並不是採用三角形而是多邊形儲存的。而教程裡的解析部分使用的是三角形。好在collada官網上提供了COLLADA Refinery,可以完成這個轉換工作。另外,某些3d軟體匯出collada時也可以選擇頂點資料採用哪種幾何形式。
B.bone的命名
教程提供的格式轉換工具,假射骨骼都是採用bone*的形式命名的,而我使用blender匯出的collada檔案,顯然不是這樣。好在教程提供了轉換工具的原始碼,這點比較好修改。
C.根節點個數
教程假定骨骼有唯一一個根節點,實際很可能不是這樣。
5.數學庫的問題
我沒有使用教程作者網站裡提供的引擎裡附帶的數學庫(懶得從引擎裡分離出來),而是從網上找了一套gmtl數學庫,結果遇到不少問題。不過個人感覺這個彎兒繞的值,弄清了一些計算機3d數學運算的基本概念。首先是齊次變換。為了表示平移變換,矩陣要使用4x4而不是3x3,向量也要使用4個分量的版本。,要注意,向量的第四維是1,矩陣的平移效果才能體現,是0的話,只是旋轉和伸縮,某些庫的預設值還就是0。
其次是行列矩陣以及矩陣的記憶體表現形式。四維向量與4x4矩陣相乘,合乎矩陣乘法規則的形式是行向量乘以行矩陣(1x4 * 4x4),或者是列矩陣乘以列向量(4x4 * 4x1),不同的數學庫,或兩者都提供,或只提供其中之一。確定了數學庫使用行矩陣(row major matrix)還是列矩陣(column major matrix),還需要確定數學庫的矩陣記憶體儲存形式。矩陣可以採用行優先儲存(row major order matrix),也可以採用列優先儲存(column major order matrix)。矩陣的記憶體表現形式一般是一16個元素的float陣列,這裡行列優先儲存的意思是,4x4的矩陣元素,是按第1、2、3、4行的順序,還是1、2、3、4列的順序,儲存到1維數組裡去。一般會採用讓矩陣裡四個向量的對應維元素儲存到線性連續空間的方式來選擇行列矩陣和行列優先儲存形式。這是因為cpu或gpu一般會提供單指令多資料命令(SIMD)來提高矩陣乘法的運算速度。如果採用上述的方案,計算矩陣與向量相乘時,就可以利用SIMD同時對四維進行計算。
這裡推薦一個解釋的比較清楚全面的網頁