Maya开发
Maya開發(fā)(一)-- 緒論 (翻譯自Maya官方文檔)2008-05-09 15:33??????? 緒論
??? Autodesk? Maya? 是一個(gè)開放的產(chǎn)品,就是說任何Autodesk以外的人都可以改變Maya現(xiàn)有的特征,或者
增加新的特性.你可以用兩個(gè)方法來修改MAYA:
???
??? MEL? -- (Maya Embedded Language Maya內(nèi)嵌語言)這是一個(gè)強(qiáng)大又簡單易學(xué)的腳本語言.可以完成大部分的操作。
??? Python?-- 這是一個(gè)強(qiáng)大又簡單易學(xué)的腳本語言,提供了Maya命令接口。
??? API -- (Application Programmer Interface 應(yīng)用程序接口)可以提供比MEL更好的性能實(shí)現(xiàn).你可以用API向MAYA
??????? 中增加新的對象,而代碼執(zhí)行的速度差不多比MEL執(zhí)行同樣的工作快10倍.當(dāng)然你可以從API里執(zhí)行MEL代碼.
??? Maya Python API -- 基于API,允許通過Python腳本語言來使用API。
???
???
??????? 總覽
??? "MAYA API"是一種提供了訪問MAYA內(nèi)部特性的"C++ API".在以下平臺下都有實(shí)現(xiàn):Microsoft? Windows?, Linux?,
and Apple? Mac OS? X. 你可以利用API來實(shí)現(xiàn)兩種代碼資源:擴(kuò)展MAYA功能的"plug-ins",或者一個(gè)可以用來訪問和
操作MAYA模型的獨(dú)立應(yīng)用程序.
???
??? "Plug-ins"被建成利用標(biāo)準(zhǔn)系統(tǒng)的功能載入MAYA的動態(tài)可重定位的庫."Plug-ins"通過訪問宿主程序MAYA的代碼空間
來工作,但不能訪問其他被載入的"Plug-ins"的代碼空間.
??? 根據(jù)操作系統(tǒng)的不同,對于建立和命名"Plug-ins"也有些限制.因此"Plug-ins"程序的后綴在各個(gè)平臺上也是不同的.
??? MAYA使用的"Plug-ins"為:
??????? * Linux: .so
??????? * Windows: .mll
??????? * Mac OS X: .lib
??? 開發(fā)工具
??? MAYA API被放在MAYA安裝目錄中的開發(fā)者工具目錄中.有一些平臺默認(rèn)是不安裝開發(fā)者工具的.這種情況下你需要在
安裝MAYA的時(shí)候進(jìn)行特別指定需要安裝開發(fā)者工具.開發(fā)者工具主要由3個(gè)部分組成:包含頭文件,庫文件和用例.
??? Include Files
??? 我們提供了一些頭文件作為MAYA的接口.頭文件存放在開發(fā)者工具目錄中的"include/maya"中.MAYA的頭文件一般以
"M"開頭.跟在"M"后面的名字表示的類型有:"Fn"表示函數(shù)集,"It"表示迭代器,"Px "表示代理類.
???
??? Libraries
??? API被封裝成MAYA各種相應(yīng)功能領(lǐng)域的庫中.這些庫有:
???????
??????? OpenMaya - 包含了基本類,定義了節(jié)點(diǎn)和命令,并裝配他們進(jìn)"Plug-ins".
??????? OpenMayaUI - 包含了生成新的用戶界面的類,比如控制器,上下文菜單和定位器等;
??????? OpenMayaAnim - 包含了動畫類,包括造型和反向動力學(xué).
??????? OpenMayaFX - "Autodesk? Dynamics?"類
??????? OpenMayaRender - 渲染類
??? 這些都是共享庫,所以可以被若干個(gè)"Plug-ins"同時(shí)使用.庫文件存放在"lib"目錄中.
???
??? Examples
??? MAYA API的用例程序包含在"devkit"目錄中.有"application"和"plug-ins"兩個(gè)文件夾."application"里包含了
獨(dú)立應(yīng)用程序的例子,而"plug-ins"則包含了插件的例子.制作應(yīng)用程序和插件的方法在不同的平臺有些不同.一般情況下
可以使用"MakeFiles"文件.在Windows和Max OS X下我們?yōu)榇蟛糠钟美峁┝薎DE的工程.
??? Documentation
??? 我們提供了豐富的MAYA API的文檔資料.主要由兩部分組成:
??????? * This technical introduction to the Maya API??? 技術(shù)解說
??????? * The API class descriptions??????????????????? 類參考
??? 根據(jù)文檔可以了解以下內(nèi)容:
??????? * The MEL and Expressions guide
??????????? MEL和表達(dá)式指南
??????? * The Maya MEL command reference
??????????? MEL命令參考
??????? * The Maya Nodes and Attributes reference. Working with Maya nodes is a normal part of programming the Maya API
??????????? MAYA節(jié)點(diǎn)和屬性參考.使用節(jié)點(diǎn)是MAYA API編程的普遍方法.
??????? * The What’s New information provided with each release
??????????? 每個(gè)發(fā)行版本的更新點(diǎn)
??????? * The Release Notes that provide items of interest for developers
??????????? 發(fā)行說明
??? 可以通過MAYA HELP來訪問這些資源(Help > Maya Help).
???
??? Other Requirements
??? 既然MAYA API是C++程序.那么你最好能理解以下內(nèi)容:
??????? * virtual functions
??????????? 虛函數(shù)
??????? * class inheritance (including multiple)
??????????? 類繼承(包括多態(tài))
??????? * stream classes
??????????? 流類型
??????? * operator methods(there are many operator methods in the Maya API)
??????????? 操作符方法(MAYA里有很多操作符方法)
???
//======================================================================================================================
//======================================================================================================================
??? 載入一個(gè)插件
??? 有兩個(gè)方法來載入或卸載插件.最簡單的方法是使用插件管理器(Plug-in Manager).
??? 從插件管理器載入插件:
??????? 1. 選擇 Window > Settings/Preferences > Plug-in Manager 菜單來打開管理器窗口來顯示已知插件列表.
??????? 2. 找到你需要的插件勾選上"loaded"或者"auto load"來載入插件.
???
??? 插件管理器使用"MAYA_PLUG_IN_PATH"環(huán)境變量來定位有效的插件來載入.
???
??? "MAYA_PLUG_IN_PATH"只在管理器窗口第一次被打開的時(shí)候進(jìn)行掃描定位,這是為了以后再次打開的時(shí)候能夠加快速度.因此,如果
在MAYA運(yùn)行的時(shí)候新建了一個(gè)插件,那有可能并不會在插件管理器內(nèi)顯示.訪問新建的插件請參照以下方法之一:
??? * 點(diǎn)選管理器窗口中的"Refresh"(刷新)按鈕來更新列表.可以使目錄再次被掃描并更新列表中的內(nèi)容.
??? * 使用"loadPlugin"MEL命令.
??? * 重啟Maya.
??? 從命令行載入插件:
??? 假設(shè)你有一個(gè)插件名字叫"hello"在"MAYA_PLUG_IN_PATH"目錄內(nèi).你可以用MEL命令"loadPlugin".
??????? loadPlugin "hello";
??? 如果在LINUX平臺下這會在"MAYA_PLUG_IN_PATH"位置尋找名叫"hello.so"的文件,Windows平臺則是"hellp.mll",而在Mac OS X下則是
??? "hello.lib".一旦找到,則會作為一個(gè)插件被載入MAYA.
???
//======================================================================================================================
//======================================================================================================================
??? 卸載插件
??? 通過MEL卸載一個(gè)插件很簡單 -- 你可以使用"unloadPlugin"命令加插件名.
??? 注意:
??? # 一個(gè)插件在被重編譯前必須卸載,否則可能導(dǎo)致MAYA崩潰.
??? # 在你可以卸載一個(gè)插件前,你必須刪除所有場景中使用到它的地方.在將插件中定義的節(jié)點(diǎn)從場景中刪除前,還需要更新刪除掉的
??????? 節(jié)點(diǎn)和執(zhí)行過的UNDO隊(duì)列命令中使用的引用.雖然這些內(nèi)容不在場景中,但是為了UNDO,其實(shí)它還在那兒.
??? # 如果你在一個(gè)插件正在使用的時(shí)候強(qiáng)行卸載.那將無法再次載入插件節(jié)點(diǎn).這是因?yàn)樵趫鼍爸械墓?jié)點(diǎn)會轉(zhuǎn)換成"Unknown"節(jié)點(diǎn),
??????? 然后在插件重載入的時(shí)候,將不被允許改變那些存在的節(jié)點(diǎn)的類型.
//======================================================================================================================
//======================================================================================================================
??? 編寫一個(gè)簡單的插件
??? 以下解說了如何編寫一個(gè)簡單的"Hello world"插件
???
??? 編寫你第一個(gè)插件
??? 當(dāng)學(xué)習(xí)一個(gè)新的計(jì)算機(jī)語言的時(shí)候,你??梢钥吹降牡谝粋€(gè)程序是"Hello world".遵循這個(gè)傳統(tǒng),我們第一個(gè)插件就是"Hello world".
只是在MAYA啟動的時(shí)候簡單得輸出"Hello world"在窗口中.
??????? #include <maya/MSimple.h>
??????? #include <maya/MIOStream.h>
??????? DeclareSimpleCommand( helloWorld, "Autodesk", "8.0");
??????? MStatus helloWorld::doIt( const MArgList& )
??????? {
??????????? cout << “Hello World\n”;
??????????? return MS::kSuccess;
??????? }
???????
??? LINUX:
??? 如果這些保存到一個(gè)helloWorld.cpp 文件中,那么可以被這樣編譯:
??????? g++402 -c -I. -I.. -I/usr/aw/maya8.0/include -I/usr/X11R6/include
??????? -m32 -O3 -pthread -pipe -D_BOOL -DLINUX -DREQUIRE_IOSTREAM -
??????? mtune=pentium4 -Wno-deprecated -fno-gnu-keywords helloCmd.cpp
??????? g++402 -shared -m32 -O3 -pthread -pipe -D_BOOL -DLINUX -
??????? DREQUIRE_IOSTREAM -mtune=pentium4 -Wno-deprecated -fno-gnu-
??????? keywords -Wl,-Bsymbolic -o helloCmd.so helloCmd.o -L/usr/aw/
??????? maya8.0/lib -lOpenMaya -lFoundation
???????
??? Windows和Mac OS X:
??? 參考章節(jié)12,設(shè)定編譯環(huán)境
???
???
??? 一旦編譯完成,你可以載入MAYA,在命令窗口內(nèi)打入"helloworld"(按回車執(zhí)行命令),然后"Hello world"會在輸出窗口中顯示.
???
???
//======================================================================================================================
//======================================================================================================================
??? 重要的插件特性
??? "Hello world"插件有幾個(gè)重要的特性.
???
??? MSimlpe.h
??? 為簡單命令行插件使用的一個(gè)特殊的頭文件.它利用"DeclareSimpleCommand"宏,接管了所有需要的工作來注冊一個(gè)MAYA新命令,但是只能
??? 創(chuàng)建一個(gè)插件來對應(yīng)一個(gè)命令.
???
??? 注意:
??????? # 很可能并且也很普遍的是,編寫一個(gè)插件來實(shí)現(xiàn)幾個(gè)特性,就像依賴圖節(jié)點(diǎn)和命令組.這樣的插件就不能使用"MSimple.h".
??????????? 你必須編寫自定義的注冊代碼來告訴MAYA插件的功能.
??????? # 這個(gè)宏主要的限制就是你只能創(chuàng)建一個(gè)非UNDO的命令.
???????
??? MStatus
??? 指示一個(gè)方法是否成功或者失敗.大部分方法都通過MStatus來返回一個(gè)狀態(tài)代碼,每一個(gè)方法的文檔都詳細(xì)介紹了可能的狀態(tài)返回值.
??? 為了避免和其他狀態(tài)代碼的命令空間沖突,所有的MStatus狀態(tài)值都被"MS"所封裝.比如"MS::kSuccess"是一個(gè)表示成功的代碼.詳細(xì)的列
??? 表在"MStatus.h"內(nèi).
???
??? 注意:
??????? API使用很少的狀態(tài)碼,如果通過MGlobal::startErrorLogging()開啟錯(cuò)誤日志系統(tǒng),則當(dāng)一個(gè)方法返回非MS::kSuccess時(shí),額外的錯(cuò)誤
??????? 信息將被輸出到日志文件中.
???????
??? DeclareSimpleCommand
??? "DeclareSimpleCommand "需要3個(gè)參數(shù):類名,作為一個(gè)命令的實(shí)現(xiàn).提供者名.命令的版本號.
???
??? "MSimple.h"內(nèi),"DeclareSimpleCommand()"宏省下了你自行編寫注冊代碼的時(shí)候,為了保持簡單性,你不能為這個(gè)命令使用UNDO方法.
所以你不能用這個(gè)宏生成一個(gè)真正的可以UNDO的命令
???
??? 注意:
??? 不管怎樣,不支持UNDO的命令不能改變場景中的狀態(tài)屬性.它們可以去查詢場景的不同視點(diǎn)位置而不能去改變它.如果一個(gè)非UNDO的命令確實(shí)
??? 改變了什么,那么MAYA的UNDO功能就會被破壞.
???
???
??? 編寫一個(gè)可以和MAYA交互的插件
??? 這和"Hello world"只有很少的差別.(既然"hello world"總是輸出同樣的內(nèi)容,你或許像寫一個(gè)可以和MAYA交互的插件.(其中一個(gè)方法是在MEL命令
行中增加參數(shù)))
???
??? 下面是另一個(gè)簡單的程序,在它的輸入內(nèi)容后打印"Hello".
???
??????? #include <maya/MSimple.h>
??????? #include <maya/MIOStream.h>
??????? DeclareSimpleCommand( hello, "Autodesk", "8.0");
??????? MStatus hello::doIt( const MArgList& args )
??????? {
??????????? cout << "Hello " << args.asString( 0 ).asChar() << endl;
??????????? return MS::kSuccess;
??????? }
???????
???????
??? 當(dāng)載入以后,輸入命令"hello neighbor"則會輸出"Hello neighbor"
???
???
??? MArgList
??? "MArgList"類提供了一種類似C和C++程序入口中"argc/argv"參數(shù)的機(jī)能.提供一個(gè)參數(shù)列表給你的函數(shù).類提供方法把參數(shù)作為各種類型來取得,
??? 比如包括了"integer","double","string",或者"vector".
???
??? 下面一個(gè)例子中,"helix"命令被定義成通過MArgList對象得到若干個(gè)參數(shù).兩個(gè)參數(shù)為"pitch"和"radius".
??????? #include <math.h>
??????? #include <maya/MSimple.h>
??????? #include <maya/MIOStream.h>
??????? #include <maya/MFnNurbsCurve.h>
??????? #include <maya/MPointArray.h>
??????? #include <maya/MDoubleArray.h>
??????? #include <maya/MPoint.h>
??????? DeclareSimpleCommand( helix, "Autodesk - Example", "3.0");
??????? MStatus helix::doIt( const MArgList& args )
??????? {
??????????? MStatus stat;
??????????? const unsigned??? deg???? = 3;??????????? // Curve Degree
??????????? const unsigned??? ncvs???? = 20;??????????? // Number of CVs
??????????? const unsigned??? spans???? = ncvs - deg;??? // Number of spans
??????????? const unsigned??? nknots??? = spans+2*deg-1;// Number of knots
??????????? double??? radius??????????? = 4.0;??????????? // Helix radius
??????????? double??? pitch???????????? = 0.5;??????????? // Helix pitch
??????????? unsigned??? i;
??????????? // Parse the arguments.
??????????? for ( i = 0; i < args.length(); i++ )
??????????????? if ( MString( "-p" ) == args.asString( i, &stat )
??????????????????????? && MS::kSuccess == stat)
??????????????? {
??????????????????? double tmp = args.asDouble( ++i, &stat );
??????????????????? if ( MS::kSuccess == stat )
??????????????????????? pitch = tmp;
??????????????? }
??????????????? else if ( MString( "-r" ) == args.asString( i, &stat )
??????????????????????? && MS::kSuccess == stat)
??????????????? {
??????????????????? double tmp = args.asDouble( ++i, &stat );
??????????????????? if ( MS::kSuccess == stat )
??????????????????????? radius = tmp;
??????????????? }
??????????? MPointArray??? controlVertices;
??????????? MDoubleArray knotSequences;
??????????? // Set up cvs and knots for the helix
??????????? //
??????????? for (i = 0; i < ncvs; i++)
??????????????? controlVertices.append( MPoint( radius * cos( (double)i ),
??????????????????? pitch * (double)i, radius * sin( (double)i ) ) );
??????????? for (i = 0; i < nknots; i++)
??????????????? knotSequences.append( (double)i );
??????????? // Now create the curve
??????????? //
??????????? MFnNurbsCurve curveFn;
??????????? MObject curve = curveFn.create( controlVertices,
??????????????????????????????????????????? knotSequences, deg,
???????????????????????????????????????????
??????? MFnNurbsCurve::kOpen,
??????????????????????????????????????????? false, false,
??????????????????????????????????????????? MObject::kNullObj,
??????????????????????????????????????????? &stat );
??????????? if ( MS::kSuccess != stat )
??????????????? cout << "Error creating curve.\n";
??????????? return stat;
??????? }
???????
???????
??? 提醒:
??? 和"argc/argv"一個(gè)重要的不同是,"MArgList"的第0個(gè)元素是命令之后的第一個(gè)參數(shù),而不是像C和C++那樣是命令的名字.
???
???
???
??? 利用插件創(chuàng)建一個(gè)曲線
??? 下面一個(gè)例子是用插件建立一個(gè)螺旋的曲線.
??????? #include <math.h>
??????? #include <maya/MIOStream.h>
??????? #include <maya/MSimple.h>
??????? #include <maya/MPoint.h>
??????? #include <maya/MPointArray.h>
??????? #include <maya/MDoubleArray.h>
??????? #include <maya/MFnNurbsCurve.h>
??????? DeclareSimpleCommand( doHelix, "Autodesk - Example", "8.0");
??????? MStatus doHelix::doIt( const MArgList& )
??????? {
??????????? MStatus stat;
??????????? const unsigned???? deg?????? = 3;???????????????? // Curve Degree
??????????? const unsigned???? ncvs????? = 20;??????????????? // Number of CVs
??????????? const unsigned???? spans???? = ncvs - deg;??????? // Number of spans
??????????? const unsigned???? nknots??? = spans+2*deg-1;???? // Number of knots
??????????? double???? radius??????????? = 4.0;?????????????? // Helix radius
??????????? double???? pitch???????????? = 0.5;?????????????? // Helix pitch
??????????? unsigned???? i;
??????????? MPointArray???? controlVertices;
??????????? MDoubleArray??? knotSequences;
??????????? // Set up cvs and knots for the helix
??????????? //
??????????? for (i = 0; i < ncvs; i++)
??????????????? controlVertices.append( MPoint( radius * cos( (double)i ),
??????????????????? pitch * (double)i, radius * sin( (double)i ) ) );
??????????? for (i = 0; i < nknots; i++)
??????????????? knotSequences.append( (double)i );
??????????? // Now create the curve
??????????? //
??????????? MFnNurbsCurve curveFn;
??????????? MObject curve = curveFn.create( controlVertices, knotSequences, deg,
??????????????????????????????????????????????? MFnNurbsCurve::kOpen, false, false,
??????????????????????????????????????????????? MObject::kNullObj, &stat );
??????????? if ( MS::kSuccess != stat )
??????????????? cout << “Error creating curve.\n”;
??????????? return stat;
??????? }
?
和MAYA進(jìn)行交互
??? MAYA的API包含了四種和MAYA進(jìn)行交互的C++對象.它們是:"wrappers", "objects", "function sets", 和"proxies".
???
??? API中的對象所有權(quán)
??? 將一個(gè)對象和函數(shù)集進(jìn)行聯(lián)合有點(diǎn)類似"wrappers".但區(qū)別是需要一樣的對象所有權(quán).在API中對象的所有權(quán)很重要.如果沒有適當(dāng)?shù)亩x,你可能
刪除一個(gè)系統(tǒng)需要的東西.或者使用了一個(gè)系統(tǒng)已經(jīng)刪除了的內(nèi)容.API"wrappers", "objects",和"function sets"消除了關(guān)于所有權(quán)的問題.
因此潛在的在一個(gè)不適當(dāng)?shù)臅r(shí)候使用一個(gè)對象,比如在系統(tǒng)已經(jīng)刪除了它的時(shí)候.這種情況被避免了.
//======================================================================================================================
//======================================================================================================================
??? MObject
??? 訪問所有的MAYA對象(curves, surfaces, DAG nodes, dependency graph nodes, lights, shaders, textures, 等.)可以通過一個(gè)叫
??? "MObject."的句柄對象.這個(gè)句柄通過一些簡單的方法來幫助檢測對象的類型."MObject"析構(gòu)函數(shù)并不刪除它所指向的MAYA對象.調(diào)用"MObject"
的析構(gòu)函數(shù)只是刪除"MObject"對象本身,因此保護(hù)了對象所有權(quán).
???
??? 重要提醒:
??? 你應(yīng)該永遠(yuǎn)不在插件運(yùn)行的時(shí)候保持一個(gè)指向"MObject"的指針.相代替的是,可以使用"MObjectHandle",當(dāng)這個(gè)對象包含了"MObject"有效信息的時(shí)候.
???
???
//======================================================================================================================
//======================================================================================================================
??? Wrappers
??? "Wrappers"作為簡單的對象存在,比如數(shù)學(xué)類(比如矢量或者矩陣),它們一般是帶構(gòu)造和析構(gòu)的C++類的完全實(shí)現(xiàn).API方法可以返回一個(gè)"wrapper",
你有責(zé)任在離開使用區(qū)間時(shí)刪除這個(gè)"wrapper".你也可以在需要的時(shí)候自由地申請釋放它們.在前面的例子中"MPointArray"和"MDoubleArray"是
"wrappers",你總是擁有你使用的"wrappers".
??? 重要提醒:
??? 把"wrappers"的聲明盡可能放在深度循環(huán)的外面.很多情況下"wrappers"的構(gòu)造函數(shù)會申請分配MAYA內(nèi)建類.因此如果在深度循環(huán)中聲明"wrapper ",
??? 則"wrapper "可能反復(fù)得被申請和釋放內(nèi)存.
??? 此提醒不適用靜態(tài)"wrapper ",比如"MGlobal".
???
???
???
//======================================================================================================================
//======================================================================================================================
??? Objects and Function Sets (對象和函數(shù)集)
??? 對象和函數(shù)集常常在一起被使用.他們被分成很容易建立所有權(quán) -- 對象總是屬于MAYA,函數(shù)集數(shù)總是屬于你.
???
??? Function sets(函數(shù)集)
??? 函數(shù)集是一種操作對象的C++類.在前面用插件生成曲線的例子中,"MFnNurbsCurve"是一個(gè)函數(shù)集,("MFn"前綴指明它)
???
??? 通過兩行代碼生成曲線:
??????? MFnNurbsCurve curveFn;
??????? MObject curve = curveFn.create( ... );
???????
??????? * MFnNurbsCurve curveFn; 創(chuàng)建一個(gè)包含了各種操作曲線對象方法的新函數(shù)集, 在這兒是為了生成新的曲線.
??????? * MObject curve = curveFn.create( ... );創(chuàng)建一個(gè)新的MAYA曲線對象來使用.
??? 如果你增加第三行:
??????? curve = curveFn.create( ... );
???
??? 那第二條曲線就被創(chuàng)建并被"curve"對象所引用,第一條曲線依然存在,但是不在被MObject對象所指向.
???
??? Proxies(代理)
??? MAYA API通過"Proxies"對象來創(chuàng)建新的MAYA對象類型."Proxies"是一個(gè)你創(chuàng)建但MAYA擁有的對象.
???
??? 一個(gè)普遍的誤解是你可以通過一個(gè)現(xiàn)有的函數(shù)集起源來創(chuàng)建一個(gè)新的對象類型.比如:"MFnNurbsSurface"起源于"MFnDagNode",你可能會覺得
??? 如果你讓"MySurface"源自"MFnDagNode",并且提供所有的對新類型面的操作方法,你可以給MAYA增加一個(gè)新的表面類.很不幸,這并不能工作.
??? 你所得到的只是一個(gè)使用新方法操作現(xiàn)有對象新的函數(shù)集.記住,函數(shù)集完全屬于你,而MAYA永遠(yuǎn)看不到也用不到他們.MAYA只能使用依賴于
??? "MObject"的對象.
???
??? Typelessness(輕類型)
??? 對象和函數(shù)集分離的一個(gè)有趣的結(jié)果是API可以進(jìn)行一個(gè)輕類型的操作.比如:
??????? MFnNurbsCurve curveFn;
??????? MObject curve = curveFn.create( ... );
??????? MFnNurbsSurface surface( curve );
???????
??? 這段代碼創(chuàng)建了一個(gè)曲線并把它傳給一個(gè)曲面操作函數(shù)集.既然"MFnNurbsSurface"只能操作表面對象,上面的代碼將什么都不做.但你可能根本不知道.
??? API的錯(cuò)誤檢測代碼按預(yù)置處理這些錯(cuò)誤.
???
??? 函數(shù)集接受任何類型的MObjects對象,如果它們不能識別的話,無論你怎么試著操作他們都會忽略他們并且返回錯(cuò)誤值.
???
//======================================================================================================================
//======================================================================================================================
??? 命名規(guī)則(Naming Conventions)
??? MAYA用前綴來表示它的類類型.
???
??? MFn??????????? 任何使用這個(gè)前綴的類是可以操作一個(gè)具體"MObjects"類型的函數(shù)集.
???
??? MIt??????????? 這是一種迭代器,比函數(shù)集更多地和"MObjects"一起.比如"MItCurveCV"被用來操作單獨(dú)的"NURBS curve CV"(而不是用"MFnNurbsCurveCV"),
??????????????? 或者迭代所有在曲線上的的CV.
???
??? MPx??????????? 代理類,被設(shè)計(jì)成用來生成用戶對象類型.
???
??? M??????????? 大部分這種類是一個(gè)"Wrappers",比如函數(shù)集是操作MAYA的內(nèi)部對象的,而"MGlobal"是一個(gè)靜態(tài)方法類,用來操作全局內(nèi)容,而不需要傳入"MObject".
???
???
//======================================================================================================================
//======================================================================================================================
??? 增加參數(shù)
??? 螺旋插件生成一個(gè)簡單的曲線,但是它總是輸出同樣的曲線.
???
??? 給曲線例子增加參數(shù).
??? 你可以稍微修改一下代碼,使你可以給曲線指定半徑和傾斜度.修改函數(shù)定義,增加參數(shù):
??????? MStatus doHelix::doIt( const MArgList& args )
??? 在變量聲明后面增加下面幾行"
??????? // Parse the arguments.
??????? for ( i = 0; i < args.length(); i++ )
??????????? if ( MString( “-p” ) == args.asString( i ) )
??????????????? pitch = args.asDouble( ++i );
??????????? else if ( MString( “-r” ) == args.asString( i ) )
??????????????? radius = args.asDouble( ++i );
???????????????
??? 這段程序讀入?yún)?shù),這樣你可以用來改變生成的螺旋的半徑和傾斜.這些修改是很簡單的:
??? "for"循環(huán)查詢所有的"MArgList"封裝了的參數(shù),兩個(gè)"if"段轉(zhuǎn)換當(dāng)前的參數(shù)(變量"i"來指定訪問)為"MString"(Maya的字符串封裝),然后把他們和兩個(gè)
??? 參數(shù)標(biāo)識相比較.
??? 如果匹配,下一個(gè)參數(shù)轉(zhuǎn)換成"double"并保存到相應(yīng)的變量內(nèi).比如:
??????? doHelix -p 0.5 -r 5
??? 生成一個(gè)半徑5個(gè)單位,傾斜為0.5個(gè)單位的螺旋.
???
???
//======================================================================================================================
//======================================================================================================================
??? 錯(cuò)誤檢測
??? 例子已經(jīng)做了很多的工作了,這時(shí)你還沒有做一些錯(cuò)誤檢測.對于例子這沒什么,不過當(dāng)制作一個(gè)產(chǎn)品級的插件時(shí),你真的需要做檢測錯(cuò)誤.
???
??? 很多方法最后都帶一個(gè)可選的參數(shù).一個(gè)指向"MStatus"變量的指針,存放狀態(tài)返回值.
???
??? 如果你用以下代碼替代螺旋例子中的參數(shù)分析代碼,那么例子將檢查并處理大部分可能的錯(cuò)誤.
???
??????? // Parse the arguments.
??????? for ( i = 0; i < args.length(); i++ )
??????? if ( MString( “-p” ) == args.asString( i, &stat )
???????????? && MS::kSuccess == stat )
??????? {
???????????? double tmp = args.asDouble( ++i, &stat );
???????????? // argument can be retrieved as a double
???????????? if ( MS::kSuccess == stat )
????????????????? pitch = tmp;
??????? }
??????? else if ( MString( “-r” ) == args.asString( i, &stat )
???????????? && MS::kSuccess == stat )
??????? {
???????????? double tmp = args.asDouble( ++i, &stat );
???????????? // argument can be retrieved as a double
???????????? if ( MS::kSuccess == stat )
????????????????? radius = tmp;
??????? }
???
??? 增加在"asString() "和"asDouble() "方法里的"&stat"參數(shù)可以檢查類型轉(zhuǎn)換操作是否成功.
???
??? 比如,當(dāng)索引大于參數(shù)個(gè)數(shù)的時(shí)候"args.asString(i, &stat)"可能返回"MS::kFailure".或者,參數(shù)不能轉(zhuǎn)換成"double"的時(shí)候,
??? "args.asDouble(++i, &stat)"操作可能會失敗.
???
???
//======================================================================================================================
//======================================================================================================================
??? MStatus 類
??? "MStatus"類可以檢測方法是否失敗.
???
??? 很多API的方法返回一個(gè)"MStatus"類的實(shí)例,或者把這實(shí)例傳回給一個(gè)可選的參數(shù)."MStatus"類包含了一個(gè)"error"方法,和一個(gè)被
??? 重載了的操作"bool",如果這實(shí)例是包含錯(cuò)誤狀態(tài)的話,以上兩者都會被傳會"false".這意味著你可以很快得檢查一個(gè)調(diào)用是否正確.
??? 比如:
??????? MStatus status = MGlobal::clearSelectionList();
??????? if (!status) {
??????????? // Do error handling
??????????? ...
??????? }
???????
??? 如果"status"包含錯(cuò)誤信息的話,你可以做以下幾件事:
???
??????? * 用"statusCode"方法來得到"MStatusCode"的枚舉來指出錯(cuò)誤的原因.
??????? * 用"errorString"方法來得到一個(gè)包含錯(cuò)誤詳細(xì)解釋的"MString".
??????? * 用"perror"方法向標(biāo)準(zhǔn)錯(cuò)誤輸出錯(cuò)誤的詳細(xì)解釋.或者是你預(yù)先提供的信息字符串.
??????? * 用重載了的相等或不相等操作和一個(gè)特定的錯(cuò)誤碼相比較.
??????? * 用"clear"方法重設(shè)置實(shí)例狀態(tài)為成功.
???????
//======================================================================================================================
//======================================================================================================================
??? 錯(cuò)誤日志
??? 就想使用"MStatus"類一樣,你可以用錯(cuò)誤日志來檢查API方法的錯(cuò)誤.
???
??? 有效或無效錯(cuò)誤日志:
??? 1.在MEL里,用帶"-errlog"標(biāo)志的"openMayaPref"命令.
??? 2.在插件里,用"MGlobal::startErrorLogging()"和"MGlobal::stopErrorLogging()"方法.
???
??? 一旦你有效了錯(cuò)誤日志,MAYA生成一個(gè)日志文件,每次一個(gè)API方法失敗的時(shí)候,MAYA將帶有可以顯示哪兒做了調(diào)用的小型堆跟蹤的錯(cuò)誤解釋寫入日志文件.
??? 默認(rèn)的文件是在當(dāng)前目錄中的"OpenMayaErrorLog"文件.這也是可以被修改的,如下:
??????? MGlobal::setErrorLogPathName().
???????
??? 提示:
??? 插件也可以使用"MGlobal::doErrorLogEntry()"方法來把它們自己的錯(cuò)誤信息加入到錯(cuò)誤日志中.
?? 總覽
??? 一個(gè)命令總是用來得到選擇表中的輸入內(nèi)容."MGlobal::getActiveSelectionList()"方法的結(jié)果包含了所有的選擇了的對象,可以
??? 很簡便地使用"MSelectionList "和"MItSelectionList"來檢查.這兩個(gè)API也可以被用來編輯選擇列表.
//================================================================================
//================================================================================
??? 一個(gè)全局的當(dāng)前選擇表可以通過"MGlobal::getActiveSelectionList()"得到一個(gè)"MSelectionList"的拷貝.
??? 除非你使用"MGlobal::setActiveSelectionList()",任何你作用于"MSelectionList"的修改都不會影響全局的選擇表.
???
??? 你也可以用"MSelectionList"創(chuàng)建你自己的選擇表,并和其他表進(jìn)行合并.包括全局表.你也可以用這個(gè)表來創(chuàng)建對象集.
???
//=================================================================================
//=================================================================================
??? MSelectionList
??? "MSelectionList"提供了讓你可以從列表內(nèi)增加或者刪除對象的方法.就像在表里遍歷對象一樣.
???
??? 比如,以下插件代碼打印所有已選擇的DAG節(jié)點(diǎn)的名字.如果你生成一個(gè)幾何體,然后選擇它,這個(gè)插件會打印每一個(gè)選擇了的對象的名字.
???
??????? #include <maya/MSimple.h>
??????? #include <maya/MGlobal.h>
??????? #include <maya/MString.h>
??????? #include <maya/MDagPath.h>
??????? #include <maya/MFnDagNode.h>
??????? #include <maya/MSelectionList.h>
??????? #include <maya/MIOStream.h>
??????? MStatus pickExample::doIt( const MArgList& )
??????? {
??????????? MDagPath??????????? node;
??????????? MObject???????????? component;
??????????? MSelectionList????? list;
??????????? MFnDagNode????????? nodeFn;
??????????? MGlobal::getActiveSelectionList( list );
??????????? for ( unsigned int index = 0; index < list.length(); index++ )
??????????? {
??????????????? list.getDagPath( index, node, component );
??????????????? nodeFn.setObject( node );
??????????????? cout nodeFn.name().asChar() << “ is selected” << endl;
??????????? }
??????????? return MS::kSuccess;
??????? }
??????? DeclareSimpleCommand( pickExample, "Autodesk", "1.0" );
??? "MFnDagNode"內(nèi)的"setObject()"方法是繼承自"MFnBase"的所有功能,用來設(shè)置當(dāng)前函數(shù)集要操作的對象.一般可以通過函數(shù)集的構(gòu)造
??? 方法來做,但是如果函數(shù)集已經(jīng)被創(chuàng)造了,或者你想改變想要操作的對象的時(shí)候,你可以用"setObject()".這比你每次需要的時(shí)候構(gòu)造
??? 析構(gòu)函數(shù)集要有效.
???
??? MAYA的選擇構(gòu)架單一化對象組件的選擇就像"CVs"之類.父對象被放進(jìn)表內(nèi),組件被組織在一起成為一個(gè)組,而不是把每個(gè)組件都放到表里.
??? 比如,如果"nurbSphereShape1"上的幾個(gè)"CVs"被選擇了,上面代碼中"list.getDagPath()"的調(diào)用將返回一個(gè)指向"nurbSphereShape1"的"MDagPath"
??? 和一個(gè)包含了所有的已選"CVs"的"MObject".
???
??? 如果你一直選擇同一個(gè)物體中的一部分,那么這個(gè)物體只在選擇表中出現(xiàn)一次.而如果你在一個(gè)物體上選擇了一些組件,然后在另外的物體上
??? 選擇一些,然后在第一個(gè)物體上再選擇一部分,那第一個(gè)物體會在表中出現(xiàn)兩次.這樣你可以通過表來檢測物體選擇的順序.
//===================================================================================
//===================================================================================
??? MItSelectionList
??? "MItSelectionList"是一個(gè)包含了已選物體的封裝類.既可以是全局選擇表的一個(gè)拷貝,也可以是你自己創(chuàng)建的一個(gè)表.
???
??? "MItSelectionList"可以讓你過濾已選物體通過指定特定的類型.("MSelectionLis"不能過濾選擇物體)
??????? MGlobal::getActiveSelectionList( list );
??????? for ( MItSelectionList listIter( list ); !listIter.isDone();
??????? listIter.next() )
??????? {
??????????? listIter.getDagPath( node, component );
??????????? nodeFn.setObject( node );
??????????? cout << nodeFn.name().asChar() << “%s is selected” << endl;
??????? }
??? "MSelectionList"的例子可以修改成用"MItSelectionList"來遍歷表.其效果和之前一樣.
???
??? 你可以簡單地修改代碼,使之能選擇特定的類型,比如,修改迭代器的構(gòu)造函數(shù)為:
??????? MItSelectionList listIter( list, MFn::kNurbsSurface )
???
??? 那么循環(huán)只能選擇"NURB"面 -- 它也會忽略"surface CVs".當(dāng)然,如果你想得到選擇了的"surface CVs",你可以這樣修改:
??????? MItSelectionList listIter( list, MFn::kSurfaceCVComponent )
???
??? 這只會得到已選的"CVs".
???
???
//==================================================================================
//==================================================================================
??? MFn::Type enumeration
??? "MFn::Type enumeration"在整個(gè)API里都被使用,用來標(biāo)識對象類型.
??????? * 函數(shù)集都有一個(gè)"apiType()"方法,可以用來檢測"MObject"所指向的對象類型.每個(gè)函數(shù)集都有一個(gè)"type()"方法可以用來檢測函數(shù)集的類型.
??????? * "MGlobal::getFunctionSetList()"可以返回一個(gè)字符串?dāng)?shù)組來顯示可以接受指定對象的函數(shù)集類型.
//==================================================================================
//==================================================================================
??? MGlobal::selectByName()
??? "MSelectionList"里的"add()"方法和"MGlobal::setActiveSelectionList()"聯(lián)合使用.提供了一個(gè)插件用來修改當(dāng)前選擇列表的方法.
???
??? 另外一個(gè)方法是使用"MGlobal::selectByName()".這會找到所有符合匹配的對象,并添加他們到當(dāng)前選擇表中.比如:
??????? MGlobal::selectByName( “*Sphere*” );
??? 選擇所有名字中有"Sphere"的物體.
???
??? 提示:
??? 你也可以用"MGlobal::select()"來添加對象到當(dāng)前選擇列表,而不需要?jiǎng)?chuàng)建"MSelectionList ".
總結(jié)
- 上一篇: 多米诺骨牌v.1MEL语言
- 下一篇: 事实上着就是MAYA4.5完全手册插件篇