Programming

[2004] Maya plugin的經驗


作者: 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.]
※ 修改: 2004/10/10 2:26:34 [219-84-11-184-adsl-tpe.dynamic.]
※ 修改: 2004/10/10 2:27:26 [219-84-11-184-adsl-tpe.dynamic.]

廣告

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s