前言 cocos2d-x 中相關部分代碼介紹 ?背景知識介紹
參考
http://www.3dkingdoms.com/weekly/weekly.php?a=4
一 簡單3d 模型支持
第一步實現對3d 模型的簡單支持,完成一個CCSprite3D 類
參考CCSprite 類 以及 CCGLProgram 代碼 主要修改 draw 方法。
添加了定點數組pos ?繪制索引數組index. 以及若干 3d 變換相關的成員方法 平移 旋轉 縮放。
對draw方法的改造,首先增加對opengl 矩陣進行計算的stdTransform, 將3d空間中的變換 矩陣乘到 MV 矩陣上面。
注意cocos2d 使用了兩種投影方式,一種是 平行投影,一種是3d 透視投影,默認使用的3d 投影, 這種方式下MV矩陣也被修改,將坐標原點移動到了屏幕的右下角。
3d繪制需要 開啟depth_test 深度測試。
之后只需要將頂點數組傳入vertexAttribPointer 中 將索引數組傳給glDrawElements 中即可.
測試時可以手動寫一個 正方體的 頂點數組數據。
注意要對模型進行一定的縮放,否則屏幕上面會看不到。
使用 畫 line 以及 畫頂點 方式 繪制 可以用來調試。
二 3d 模型 基本變換支持
http://en.wikipedia.org/wiki/Transformation_matrix
cocos2dx 中使用kazmath 這個數學庫,這個庫中的矩陣kmMat4使用列優先的方式存儲,即0 1 2 3 存儲的是 矩陣第一列數據。
對應平移變換只需要修改 最后一列的 前3行數據即可,分別對應x y z 平移。
http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
對于旋轉,一般使用四元式進行計算,因此對于旋轉可以先按照四元式進行計算,最后轉化成一個矩陣即可。
四元式 通過對旋轉軸和相對于軸的旋轉角度來表示(通過一些sin cos計算),兩個四元式之間的插值使用圓插值(slerp).
基本的 x y z 軸的旋轉矩陣 可以參考2維度旋轉矩陣的構造方法。
http://onlinemca.com/mca_course/kurukshetra_university/semester5/computergraphics/three_d_transformation.php
對于縮放直接修改矩陣主對角線上面的值即可。
下面這些矩陣對頂點的計算 都是按照 行優先矩陣 左乘以 頂點列向量, 相當于列優先矩陣 右乘以 頂點行向量 來計算結果的。在給opengl 傳入矩陣的時候 是以 列優先的方式傳入數據的。 ?http://www.opengl.org/archives/resources/faq/technical/transformations.htm
在kazmath 這個庫里面 矩陣是以列優先方式存儲,矩陣相乘的時候第一個矩陣的第一行 乘以 第二個矩陣的第一列 得到第一個元素,即是第一個矩陣左乘第二個矩陣。?
http://www.mindcontrol.org/~hplus/graphics/matrix-layout.html
貌似在direct3d中傳入的矩陣數據是按照行優先的順序的,因此在direct中如果要做兩個矩陣的乘法,第一個矩陣左乘第二個矩陣,則選取的矩陣元素和opengl是不同的。
當然這里使用的左乘 是數學上面的左乘的概念,即用一個矩陣的 第一行 乘以 第二個矩陣的第一列 得到第一個元素。
注意矩陣乘法是不可以交換了,因此對于這三種變換,不同的乘順序會產生不同的結果。舉例如下:
旋轉矩陣 左乘 平移矩陣,則旋轉矩陣中的值將會影響到平移的值,而平移的數值不會影響結果中的旋轉部分的值,結果就是在世界空間中 對象是旋轉一定角度之后,沿著這個角度進行平移的。
如果平移矩陣 左乘 旋轉矩陣, 平移的值不會影響結果中的旋轉部分, 旋轉也不會影響平移。結果就是物體現在本地旋轉,但是之后 還是沿著世界坐標中原來的軸進行平移。
先考慮 縮放矩陣 左乘 旋轉矩陣 結果就是 相當于在原來的旋轉矩陣上面 同一行 乘以一個相同的系數, 這個矩陣在作用到頂點的時候 ?這個 系數可以提取出來,則相當于 對頂點先進行了旋轉 接著 還是按照原來的 世界坐標的方向 進行縮放, 這樣得到的是一個 切拉伸的效果,這樣物體會變形。
那么 旋轉矩陣 左乘 縮放 矩陣 得到的結果就和上面不同,因此應該是物體旋轉之后,相應的縮放軸也跟著旋轉了,因此縮放 不是沿著世界軸進行的,而是沿著物體本身的本地坐標軸進行的,這樣物體不會邊形。
接著考慮縮放左乘 平移矩陣 , 結果中的縮放部分沒有變化,但是平移部分會被改變,結果就是 物體還是按照原來的比例縮放,但是 新的平移位移的時候相對于 原來的平移位移會產生一定比例的縮放。
如果是 平移 左乘 縮放矩陣 ?結果中平移部分 和 縮放部分都不會發生改變, 結果就是 物體在世界坐標空間中 按照原來的比例 縮放 , 接著平移正常的位移。
可以總結出來 平移 左乘 另外的矩陣 不過影響原來矩陣的結果, 而別的兩種矩陣左乘平移矩陣 會影響平移的結果。縮放 左乘 旋轉 會產生物體的邊形, 而旋轉左乘縮放 會保持物體的形狀和單純的進行縮放的物體形狀是一致的。
因此如果你的目標是保證世界空間中平移不變則用平移矩陣左乘其它矩陣,如果是要保證物體的縮放形狀不變則 用 旋轉矩陣左乘 縮放矩陣。
如果要保持這兩個不變性的話 矩陣乘法的順序就是 平移 * 旋轉 * 縮放
http://gamedev.stackexchange.com/questions/16719/what-is-the-correct-order-to-multiply-scale-rotation-and-translation-matrices-f
當然要根據自身想要的結果來調整矩陣的乘法順序,并且可以通過增加父子變換的關系來控制矩陣乘法順序。
一般情況是 父親矩陣 左乘于 孩子矩陣 則結果就是 父親在世界空間的平移 得到保持, 父親縮放會導致旋轉的孩子發生變形,父親的旋轉 會影響孩子自身的平移方向。
按照專業的說法叫做 孩子的變換矩陣作用在孩子節點自身的局部空間 而 父親矩陣 會對孩子局部空間進行變換。
三 骨骼動畫
本質上骨骼只是一個矩陣變換,如果要查看一個骨骼則觀察其對應的矩陣即可。但是這種方式非常不直觀,如何通過圖像直觀表現這種矩陣變換呢?
這里首先要明確表現和本質之間的區別,矩陣變換及其對應的3d骨骼對象不能等價。骨骼的作用只是施展一種變換到一個對象身上,至于這個對象當前的狀態是什么并不關心,因此需要手動的對對象設定一個初始化的狀態,而后續的狀態通過這種骨骼矩陣變換來生成。
因此問題分成兩個部分,如何描述這種初始化狀態,如何描述這個矩陣變換。
骨骼分成兩個端點 頭和 尾部,之間有一定長度連接,并且這兩個點之間有一定的旋轉方向。
矩陣變換比較簡單,可以通過一個四元式和一個3維向量, 以及一個骨骼長度來描述。
將骨骼的一端做為原點,這里我設定骨骼沿著x 軸方向,而骨骼長度就是lenght,offset表示孩子骨骼相對于父親骨骼的 結束端點的 位置偏移,通常這個偏移量為0.
這樣矩陣變換的計算方法就是?
外部矩陣 * 父親骨骼平移矩陣 * 父親骨骼旋轉矩陣 * x軸方向 length長度 平移矩陣 * 孩子骨骼的平移矩陣 * 孩子骨骼旋轉矩陣?
上面就能計算到 一個孩子骨骼的變換矩陣了。抽取其中的元素,可以得到每根骨骼的變換矩陣的計算方法是
外部矩陣 * 平移矩陣 * 旋轉矩陣?
而傳入給孩子骨骼的 矩陣就是 ?外部矩陣 * 平移矩陣 * 旋轉矩陣 * x軸方向長度length 平移矩陣
這里的length存在的主要目的是為了方便的描述旋轉,因為對于長度0的骨骼來講 就沒辦法指定其旋轉方向了。
解決了矩陣變換的描述方法 接著需要描述骨骼初始狀態以及和mesh綁定時的初始狀態
首先建模的時候會把骨骼的父子關系確定每個骨骼初始的旋轉 長度 平移這些參數確定, 這里我們假設骨骼動畫只有旋轉, 這樣的話 長度可以存儲到上面提到的length里面。
這時候如何存儲初始的旋轉矩陣呢? 我們為每一個骨骼分配了一個額外的矩陣,這個矩陣里面存放 骨骼初始 骨骼的初始平移矩陣 左乘 旋轉矩陣 ?的逆 矩陣。
這樣在對一個骨骼上面的定點進行變換的時候,如果骨骼在初始狀態,那么對定點的變換就是 單位矩陣,通過上面計算的逆矩陣 * 骨骼當前的變換矩陣 就會得到一個單位矩陣 而這個單位矩陣 再作用到 定點上 定點就不會運動了。這樣就保證了 在骨骼的初始狀態下 骨骼上綁定的 頂點 也是在初始狀態, 不會運動。
上面計算的骨骼逆矩陣是骨骼局部空間的逆矩陣 因此是不夠用的,對于子骨骼來講 其變換矩陣是經過父親層層傳遞的, 因此一個子骨骼的逆矩陣實際的逆向矩陣是 子局部逆向矩陣 * 父親逆向矩陣
這時候 對于 計算孩子骨骼的實際變換矩陣就是 ? 子局部逆向矩陣 * 父親逆向矩陣 * 父親傳到的變換矩陣 * 子局部變化矩陣
這樣如果 父親 孩子骨骼都在bind位置時候,孩子上面的mesh 定點也是在bind位置的。
因此對于一個骨骼描述的數據就包括
rotate 四元式骨骼局部旋轉
offset 3維度向量 骨骼局部偏移
length 長度 骨骼長度
reverse ?kmMat4 局部逆矩陣
mat 計算的實際變換矩陣 用于給mesh定點使用?
child 骨骼的孩子骨骼
parent 骨骼的父親
id 骨骼的編號
name 骨骼的名字
四:blender中的骨骼動畫導出 并在cocos2dx 中導入?
blender 支持python腳本有比較好的擴展性 因此嘗試導出blender中的模型和動畫數據 在游戲引擎中使用
需要導出的數據包括
定點數據 包括 定點位置 定點綁定的骨骼編號 以及權重
面數據 每個三角面 由哪幾個編號的定點構成
骨骼數據 骨骼在bind姿勢下面 每個骨骼的旋轉值, 偏移值, 長度信息, 骨骼的父親信息
動畫信息 不同frame下 每個骨骼的 旋轉 長度 偏移 信息
?