作者 DickG (龍龍) 站內 GameSchool
標題 Re: 推薦台大資工的原因
時間 Sun Oct 10 02:25:29 2004
───────────────────────────────────────
Brilliance Studio: Shuen-Huei Guan (Drake)
前言:
一口氣問了一堆問題,還是三年前的事了,有多少印象寫
多少好了。
先寫 Maya exporter 的心路歷程好了。程式實作與問題
解決的過程已經有點不大記得了,所以內容在技術層面上
的著墨不多。不過這也都是三年前的情況,看的人不要太
嚴肅看待一些數字或細節。
前置作業:
我們的團隊(Brilliance Studio )在最後的一位台藝大
同學的加入後,才算正式進入有 3D 資料的這個階段,當
時我們考慮的有 3D Max 和 Maya 。他建議使用 Maya ,
原因好像是「他只會用 Maya 」。因為美術總監都這麼說
了,就沒啥好異議的了。
首當其衝的問題:如何把美術辛苦製作出來的 3D 模型和
程式整合。我經過了約一個禮拜的研究後,覺得非得自定
一個自己用的格式不可,加上在這之前有自行寫過 3D Max
的 plugin ,那時寫得很愉快,於是乎覺得 Maya 應該也
ok,那次會議我的一句「Maya exporter 交給我就行了」
可把我害慘了。
要寫的 Maya plugin (exporter) 主要的功能如下:
1.要處理的 maya 檔有兩種
static model: 場景、物品、武器…
animated character: 有使用了 rigid-bind 的角色
2.正確取得 vertex set, face set, normal set, uv set
其中 uv 只取第一組,不考慮 multi-texture。
3.取出 skeleton 的資訊,這方面主要就是 joints 以及
之間的 hierarchical relationship
4.角色的動作方面,原打算只取出每個設 key 的時間點
,再自行仿照 maya 作內插的方式,來得出任意一個時
間點的 skeleton(亦即是每個 joint 相對於 parent
的 transformation)。後來發覺到 maya 的內插預設是
非線性的,雖然有請美術把動作方面的內插都改為線性
內插,但為了降低寫 exporter 的困難度,於是改成每
個 frame 都取出它的 skeleton 來。
5.美術有使用 paint skin weights tool,所以每個 vertex
的 binding weight 得正確取出來。
6.我們經過一段時間的 survey 後,決定使用 Cal3D
(一個 open source 的 character animation library)
作為處理 animation 的底層。Cal3D 有幾個特點:
(1) 它把資料拆成三部分:mesh, skeleton, animation
transformation(簡稱 anim)。
(2) 每個 anim 獨立一個檔,是以一個角色如果擁有 5
個動作的話(ex, stand1, stand2, run, die, fight)
,就得有五個相對應的 anim 檔。
(3) Cal3D 提供 anim 之間的 blending ,有點像連續
播放的前後兩首音樂之間的 fade-in/fade-out 。
舉個例子,我們每個角色都只有上述提到的 5 個
動作,但我們可以透過 Cal3D 來做到「邊跑邊打
人」(walk + fight)這個動作。而這也是我們使
用 Cal3D 的主要原因之一。
(4) Cal3D 有提供 level-of-detail,這是我們選它的
另一個主要原因。
(5) 很遺憾地,Cal3D 提供的 exporter 不包括 maya
在內。
於是乎在寫 maya exporter 之前,我們完成了以下幾件
事:
1.我們確定下來把 static model 和 animated character
分開來處理,這避免掉一些不必要的問題。雖然後來我
們還是把 exporter 寫成一個有 UI 的 plugin ,你可
以在裏頭選要 export 的是 static 還是 animated 的。
2.不論是 static 還是 animated ,我們都已經定好了要
{ 輸出的格式了,且確定不會作大變更。
3.由於寫 maya exporter 和把 Cal3D 整合進我們的
3D Engine 兩件事都不容易,但其間的耦合性又不高(
除了需要一個 animation player 來驗證 export 出來
的資料是不是對的以外),所以兩邊可以同時進行。
一切準備就緒後,就開始動工了。
實作概述:
首先參考 Maya 附的一個範例 exporter: lepTranslator
,很快地就把 static 的部分搞定了。比較欠缺的是 texture
方面的資訊。後來我們只抓出每個 vertex 的 uv 資訊,
有關 material 和 multi-texture 的部分先不理會,而
且強制要求每個 vertex 只能有一組 uv (這裏指的是,
同一個 vertex 在不同的 face 裏時,它的 uv 都要一樣
。因為 Maya 的彈性很大,是可以讓一個 vertex 在每一
個相連的 face 上有不同的 uv 的。)
vertex 的 binding weight 就沒那麼簡單了,由於它被
儲存在 property 裏頭(Maya 裏叫 Plug ),所以得先
挖出相對應的 plug ,再由裏頭翻出要的資料來。這也是
為什麼我們使用 rigid-bind 而不是使用 smooth-bind
的主要原因之一:smooth-bind 的儲存方式更複雜 @@
我只記得那時 binding weight 是被存在 cluster 一類
的 function class (or function set) 裏。
附上一段當時寫的,用來取出 binding weight 的 code:
m_oMeshFS << "Selection list length " << clusterMeshSetList.length() << endl;
for (size_t kk = 0; kk < clusterMeshSetList.length(); ++kk)
{
MDagPath mypath;
MObject components;
MFloatArray weights;
clusterMeshSetList.getDagPath(kk,mypath,components);
m_oMeshFS << "\t" << kk << ": " << mypath.partialPathName().asChar() <<
endl;
MFnWeightGeometryFilter cluster(m_oObj);
cluster.getWeights(mypath,components,weights);
m_oMeshFS << "\t\tWeight: ";
for (size_t ww = 0 ; ww < weights.length(); ++ww)
{
m_oMeshFS << weights[ww] << " ";
}
m_oMeshFS << endl;
}
後記:
* 寫的過程中受挫很大,應該說從來都沒有使用一套系統
會使用得這麼不順手,即便是看過後就會忘了的 MFC
都沒那麼累人。我想主要是那時相關文件實在太少了吧
,而且 Maya 內部使用了 wrapping class (or function
class ),與一般的 OO 概念很不一樣,加上每個 node
存的資料又是以 property 的方式,是以存取方式變得
很複雜。下頭舉個大致的例子:
假設 mesh 這個 node 有個 property 叫 uv_set 。
in traditional OO:
MMesh* oMesh = (MMesh*)oObject;
const UV_SET* cpUV = oMesh->getUVSet ();
in Maya functional class:
if( MS::kFailure == prepairDagNode( m_oDagNode, m_oObj ) ) {
return (MS::kFailure);
}
if( MS::kFailure == prepairDependencyNode( m_oDependNode, m_oObj ) ) {
return (MS::kFailure);
}
if( MS::kFailure == prepairDagPath( m_oDagPath, m_oDagNode ) ) {
return (MS::kFailure);
}
// 使用 functional class 來存取
MFnMesh mesh(m_oDagPath, &status);
int iPolyNum = mesh.numPolygons (&status);
int iVertexNum = mesh.numVertices (&status);
MIntArray aUVIndex(iVertexNum, -1);
//&&&&
MString str;
int iUVNum = mesh.numUVs (str, &status);
status = mesh.getUVs (aU, aV);
// 有時無法直接有類似 getUVs 這類的 method 可用時
// 得先取出 mesh 的 property members 出來,再由裏
// 頭找出你所要的那個 property 再轉換成你要的型態
* 為了寫它,我的桌面除了 Maya 和 Visual Studio ,還
開了數十頁的 Maya document pages ,最高紀錄是同時
間有二十多個視窗處於使用中。
* 當初在 schedule 上頭,我畫上的時間是兩週完成 maya
exporter,但最後卻花了快兩個月。雖然這期間同時進
行一些其它方面的 coding ,但過程常常想叫「媽呀」。
* 一兩年後,出了本
Complete Maya Programming:
An Extensive Guide to MEL and the C++ API
是本非常入門,且也是唯一一本的 maya programming
好書。
* 寫的過程中,當發覺一直取不出要的資料時,就會把檔
案存成 .ma 檔 (maya scene file in ascii) ,然後
我會和我們的美術總監兩個人一行一行猜它的 format
,猜出關鍵的地方後,我再反推回去它可能位在哪個
class/object/function class/property 裏的哪個
member data 裏。
* 現在想想,那時候的過程真是「遠古且克難得很」 ^^'
* 那時寫好後 demo 給台大資工多媒體實驗室的教授看,
他說是全台灣前十位寫出來的吧,就覺得很爽 XD
* 目前這方面的資料很多,已經有不少 lib 有提供 Maya
exporter 了,像是 Ogre (3D Engine), DirectX,
WildMagic (3D Engine), ...
後序:
* Maya 的架構實在很複雜,雖然已經有些商業軟體方便
你做資料的轉換與使用(ex, PolyTrans) ,但這些軟
體支援的程式還有待商議(至少我未來工作的地方就發
覺 PolyTrans 不符合需求),但我覺得 Maya 比其它
3D Package 來得有「玩賞」的價值在。不論是使用它
的 API 或是 MEL (Maya Embedded Language) 來開發
相關輔助程式,最好的情況是你擁有兩顆不同的腦袋,
一顆裝 programming/computer graphics/OO ,另一顆
裝 Maya experience ,這樣會讓你寫的過程中好過一
些,再不然,有位很會操作 Maya 的美術人員在你身體
可以讓你不用一直自言自語。
* 出國參加了兩次 SIGGRAPH 、聽了幾場台灣數位內容ooxx
辦的講座,與幾位在國外工作十年有餘的人聊過後,發
覺懂得 Maya 的操作與曉得怎麼寫 Maya plugin 的人
現在是比較有價值的,理由也很簡單:它實在很難。這
種人在 hollywood 裏叫 technical software 之類的
,是 film/game company 很搶手的人,鼓勵有志朝這
方面發展的人,好好加強你的「美術工匠與程式工匠這
兩邊的整合」。
當時的參考資料:
* http://www.highend3d.com/
* http://cal3d.sourceforge.net/
* http://www.ewertb.com/maya/
--
※ Origin: 巴哈姆特<bbs.gamer.com.tw> ◆ From: 219-84-11-184-adsl-tpe.dynamic.
※ 修改: 2004/10/10 2:26:25 [219-84-11-184-adsl-tpe.dynamic.]