Maya開發(一)-- 緒論 (翻譯自Maya官方文檔)2008-05-09 15:33??????? 緒論
??? Autodesk? Maya? 是一個開放的產品,就是說任何Autodesk以外的人都可以改變Maya現有的特征,或者
增加新的特性.你可以用兩個方法來修改MAYA:
???
??? MEL? -- (Maya Embedded Language Maya內嵌語言)這是一個強大又簡單易學的腳本語言.可以完成大部分的操作。
??? Python?-- 這是一個強大又簡單易學的腳本語言,提供了Maya命令接口。
??? API -- (Application Programmer Interface 應用程序接口)可以提供比MEL更好的性能實現.你可以用API向MAYA
??????? 中增加新的對象,而代碼執行的速度差不多比MEL執行同樣的工作快10倍.當然你可以從API里執行MEL代碼.
??? Maya Python API -- 基于API,允許通過Python腳本語言來使用API。
???
???
??????? 總覽
??? "MAYA API"是一種提供了訪問MAYA內部特性的"C++ API".在以下平臺下都有實現:Microsoft? Windows?, Linux?,
and Apple? Mac OS? X. 你可以利用API來實現兩種代碼資源:擴展MAYA功能的"plug-ins",或者一個可以用來訪問和
操作MAYA模型的獨立應用程序.
???
??? "Plug-ins"被建成利用標準系統的功能載入MAYA的動態可重定位的庫."Plug-ins"通過訪問宿主程序MAYA的代碼空間
來工作,但不能訪問其他被載入的"Plug-ins"的代碼空間.
??? 根據操作系統的不同,對于建立和命名"Plug-ins"也有些限制.因此"Plug-ins"程序的后綴在各個平臺上也是不同的.
??? MAYA使用的"Plug-ins"為:
??????? * Linux: .so
??????? * Windows: .mll
??????? * Mac OS X: .lib
??? 開發工具
??? MAYA API被放在MAYA安裝目錄中的開發者工具目錄中.有一些平臺默認是不安裝開發者工具的.這種情況下你需要在
安裝MAYA的時候進行特別指定需要安裝開發者工具.開發者工具主要由3個部分組成:包含頭文件,庫文件和用例.
??? Include Files
??? 我們提供了一些頭文件作為MAYA的接口.頭文件存放在開發者工具目錄中的"include/maya"中.MAYA的頭文件一般以
"M"開頭.跟在"M"后面的名字表示的類型有:"Fn"表示函數集,"It"表示迭代器,"Px "表示代理類.
???
??? Libraries
??? API被封裝成MAYA各種相應功能領域的庫中.這些庫有:
???????
??????? OpenMaya - 包含了基本類,定義了節點和命令,并裝配他們進"Plug-ins".
??????? OpenMayaUI - 包含了生成新的用戶界面的類,比如控制器,上下文菜單和定位器等;
??????? OpenMayaAnim - 包含了動畫類,包括造型和反向動力學.
??????? OpenMayaFX - "Autodesk? Dynamics?"類
??????? OpenMayaRender - 渲染類
??? 這些都是共享庫,所以可以被若干個"Plug-ins"同時使用.庫文件存放在"lib"目錄中.
???
??? Examples
??? MAYA API的用例程序包含在"devkit"目錄中.有"application"和"plug-ins"兩個文件夾."application"里包含了
獨立應用程序的例子,而"plug-ins"則包含了插件的例子.制作應用程序和插件的方法在不同的平臺有些不同.一般情況下
可以使用"MakeFiles"文件.在Windows和Max OS X下我們為大部分用例提供了IDE的工程.
??? Documentation
??? 我們提供了豐富的MAYA API的文檔資料.主要由兩部分組成:
??????? * This technical introduction to the Maya API??? 技術解說
??????? * The API class descriptions??????????????????? 類參考
??? 根據文檔可以了解以下內容:
??????? * The MEL and Expressions guide
??????????? MEL和表達式指南
??????? * 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節點和屬性參考.使用節點是MAYA API編程的普遍方法.
??????? * The What’s New information provided with each release
??????????? 每個發行版本的更新點
??????? * The Release Notes that provide items of interest for developers
??????????? 發行說明
??? 可以通過MAYA HELP來訪問這些資源(Help > Maya Help).
???
??? Other Requirements
??? 既然MAYA API是C++程序.那么你最好能理解以下內容:
??????? * virtual functions
??????????? 虛函數
??????? * class inheritance (including multiple)
??????????? 類繼承(包括多態)
??????? * stream classes
??????????? 流類型
??????? * operator methods(there are many operator methods in the Maya API)
??????????? 操作符方法(MAYA里有很多操作符方法)
???
//======================================================================================================================
//======================================================================================================================
??? 載入一個插件
??? 有兩個方法來載入或卸載插件.最簡單的方法是使用插件管理器(Plug-in Manager).
??? 從插件管理器載入插件:
??????? 1. 選擇 Window > Settings/Preferences > Plug-in Manager 菜單來打開管理器窗口來顯示已知插件列表.
??????? 2. 找到你需要的插件勾選上"loaded"或者"auto load"來載入插件.
???
??? 插件管理器使用"MAYA_PLUG_IN_PATH"環境變量來定位有效的插件來載入.
???
??? "MAYA_PLUG_IN_PATH"只在管理器窗口第一次被打開的時候進行掃描定位,這是為了以后再次打開的時候能夠加快速度.因此,如果
在MAYA運行的時候新建了一個插件,那有可能并不會在插件管理器內顯示.訪問新建的插件請參照以下方法之一:
??? * 點選管理器窗口中的"Refresh"(刷新)按鈕來更新列表.可以使目錄再次被掃描并更新列表中的內容.
??? * 使用"loadPlugin"MEL命令.
??? * 重啟Maya.
??? 從命令行載入插件:
??? 假設你有一個插件名字叫"hello"在"MAYA_PLUG_IN_PATH"目錄內.你可以用MEL命令"loadPlugin".
??????? loadPlugin "hello";
??? 如果在LINUX平臺下這會在"MAYA_PLUG_IN_PATH"位置尋找名叫"hello.so"的文件,Windows平臺則是"hellp.mll",而在Mac OS X下則是
??? "hello.lib".一旦找到,則會作為一個插件被載入MAYA.
???
//======================================================================================================================
//======================================================================================================================
??? 卸載插件
??? 通過MEL卸載一個插件很簡單 -- 你可以使用"unloadPlugin"命令加插件名.
??? 注意:
??? # 一個插件在被重編譯前必須卸載,否則可能導致MAYA崩潰.
??? # 在你可以卸載一個插件前,你必須刪除所有場景中使用到它的地方.在將插件中定義的節點從場景中刪除前,還需要更新刪除掉的
??????? 節點和執行過的UNDO隊列命令中使用的引用.雖然這些內容不在場景中,但是為了UNDO,其實它還在那兒.
??? # 如果你在一個插件正在使用的時候強行卸載.那將無法再次載入插件節點.這是因為在場景中的節點會轉換成"Unknown"節點,
??????? 然后在插件重載入的時候,將不被允許改變那些存在的節點的類型.
//======================================================================================================================
//======================================================================================================================
??? 編寫一個簡單的插件
??? 以下解說了如何編寫一個簡單的"Hello world"插件
???
??? 編寫你第一個插件
??? 當學習一個新的計算機語言的時候,你常可以看到的第一個程序是"Hello world".遵循這個傳統,我們第一個插件就是"Hello world".
只是在MAYA啟動的時候簡單得輸出"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:
??? 如果這些保存到一個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:
??? 參考章節12,設定編譯環境
???
???
??? 一旦編譯完成,你可以載入MAYA,在命令窗口內打入"helloworld"(按回車執行命令),然后"Hello world"會在輸出窗口中顯示.
???
???
//======================================================================================================================
//======================================================================================================================
??? 重要的插件特性
??? "Hello world"插件有幾個重要的特性.
???
??? MSimlpe.h
??? 為簡單命令行插件使用的一個特殊的頭文件.它利用"DeclareSimpleCommand"宏,接管了所有需要的工作來注冊一個MAYA新命令,但是只能
??? 創建一個插件來對應一個命令.
???
??? 注意:
??????? # 很可能并且也很普遍的是,編寫一個插件來實現幾個特性,就像依賴圖節點和命令組.這樣的插件就不能使用"MSimple.h".
??????????? 你必須編寫自定義的注冊代碼來告訴MAYA插件的功能.
??????? # 這個宏主要的限制就是你只能創建一個非UNDO的命令.
???????
??? MStatus
??? 指示一個方法是否成功或者失敗.大部分方法都通過MStatus來返回一個狀態代碼,每一個方法的文檔都詳細介紹了可能的狀態返回值.
??? 為了避免和其他狀態代碼的命令空間沖突,所有的MStatus狀態值都被"MS"所封裝.比如"MS::kSuccess"是一個表示成功的代碼.詳細的列
??? 表在"MStatus.h"內.
???
??? 注意:
??????? API使用很少的狀態碼,如果通過MGlobal::startErrorLogging()開啟錯誤日志系統,則當一個方法返回非MS::kSuccess時,額外的錯誤
??????? 信息將被輸出到日志文件中.
???????
??? DeclareSimpleCommand
??? "DeclareSimpleCommand "需要3個參數:類名,作為一個命令的實現.提供者名.命令的版本號.
???
??? "MSimple.h"內,"DeclareSimpleCommand()"宏省下了你自行編寫注冊代碼的時候,為了保持簡單性,你不能為這個命令使用UNDO方法.
所以你不能用這個宏生成一個真正的可以UNDO的命令
???
??? 注意:
??? 不管怎樣,不支持UNDO的命令不能改變場景中的狀態屬性.它們可以去查詢場景的不同視點位置而不能去改變它.如果一個非UNDO的命令確實
??? 改變了什么,那么MAYA的UNDO功能就會被破壞.
???
???
??? 編寫一個可以和MAYA交互的插件
??? 這和"Hello world"只有很少的差別.(既然"hello world"總是輸出同樣的內容,你或許像寫一個可以和MAYA交互的插件.(其中一個方法是在MEL命令
行中增加參數))
???
??? 下面是另一個簡單的程序,在它的輸入內容后打印"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;
??????? }
???????
???????
??? 當載入以后,輸入命令"hello neighbor"則會輸出"Hello neighbor"
???
???
??? MArgList
??? "MArgList"類提供了一種類似C和C++程序入口中"argc/argv"參數的機能.提供一個參數列表給你的函數.類提供方法把參數作為各種類型來取得,
??? 比如包括了"integer","double","string",或者"vector".
???
??? 下面一個例子中,"helix"命令被定義成通過MArgList對象得到若干個參數.兩個參數為"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"一個重要的不同是,"MArgList"的第0個元素是命令之后的第一個參數,而不是像C和C++那樣是命令的名字.
???
???
???
??? 利用插件創建一個曲線
??? 下面一個例子是用插件建立一個螺旋的曲線.
??????? #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進行交互
??? MAYA的API包含了四種和MAYA進行交互的C++對象.它們是:"wrappers", "objects", "function sets", 和"proxies".
???
??? API中的對象所有權
??? 將一個對象和函數集進行聯合有點類似"wrappers".但區別是需要一樣的對象所有權.在API中對象的所有權很重要.如果沒有適當的定義,你可能
刪除一個系統需要的東西.或者使用了一個系統已經刪除了的內容.API"wrappers", "objects",和"function sets"消除了關于所有權的問題.
因此潛在的在一個不適當的時候使用一個對象,比如在系統已經刪除了它的時候.這種情況被避免了.
//======================================================================================================================
//======================================================================================================================
??? MObject
??? 訪問所有的MAYA對象(curves, surfaces, DAG nodes, dependency graph nodes, lights, shaders, textures, 等.)可以通過一個叫
??? "MObject."的句柄對象.這個句柄通過一些簡單的方法來幫助檢測對象的類型."MObject"析構函數并不刪除它所指向的MAYA對象.調用"MObject"
的析構函數只是刪除"MObject"對象本身,因此保護了對象所有權.
???
??? 重要提醒:
??? 你應該永遠不在插件運行的時候保持一個指向"MObject"的指針.相代替的是,可以使用"MObjectHandle",當這個對象包含了"MObject"有效信息的時候.
???
???
//======================================================================================================================
//======================================================================================================================
??? Wrappers
??? "Wrappers"作為簡單的對象存在,比如數學類(比如矢量或者矩陣),它們一般是帶構造和析構的C++類的完全實現.API方法可以返回一個"wrapper",
你有責任在離開使用區間時刪除這個"wrapper".你也可以在需要的時候自由地申請釋放它們.在前面的例子中"MPointArray"和"MDoubleArray"是
"wrappers",你總是擁有你使用的"wrappers".
??? 重要提醒:
??? 把"wrappers"的聲明盡可能放在深度循環的外面.很多情況下"wrappers"的構造函數會申請分配MAYA內建類.因此如果在深度循環中聲明"wrapper ",
??? 則"wrapper "可能反復得被申請和釋放內存.
??? 此提醒不適用靜態"wrapper ",比如"MGlobal".
???
???
???
//======================================================================================================================
//======================================================================================================================
??? Objects and Function Sets (對象和函數集)
??? 對象和函數集常常在一起被使用.他們被分成很容易建立所有權 -- 對象總是屬于MAYA,函數集數總是屬于你.
???
??? Function sets(函數集)
??? 函數集是一種操作對象的C++類.在前面用插件生成曲線的例子中,"MFnNurbsCurve"是一個函數集,("MFn"前綴指明它)
???
??? 通過兩行代碼生成曲線:
??????? MFnNurbsCurve curveFn;
??????? MObject curve = curveFn.create( ... );
???????
??????? * MFnNurbsCurve curveFn; 創建一個包含了各種操作曲線對象方法的新函數集, 在這兒是為了生成新的曲線.
??????? * MObject curve = curveFn.create( ... );創建一個新的MAYA曲線對象來使用.
??? 如果你增加第三行:
??????? curve = curveFn.create( ... );
???
??? 那第二條曲線就被創建并被"curve"對象所引用,第一條曲線依然存在,但是不在被MObject對象所指向.
???
??? Proxies(代理)
??? MAYA API通過"Proxies"對象來創建新的MAYA對象類型."Proxies"是一個你創建但MAYA擁有的對象.
???
??? 一個普遍的誤解是你可以通過一個現有的函數集起源來創建一個新的對象類型.比如:"MFnNurbsSurface"起源于"MFnDagNode",你可能會覺得
??? 如果你讓"MySurface"源自"MFnDagNode",并且提供所有的對新類型面的操作方法,你可以給MAYA增加一個新的表面類.很不幸,這并不能工作.
??? 你所得到的只是一個使用新方法操作現有對象新的函數集.記住,函數集完全屬于你,而MAYA永遠看不到也用不到他們.MAYA只能使用依賴于
??? "MObject"的對象.
???
??? Typelessness(輕類型)
??? 對象和函數集分離的一個有趣的結果是API可以進行一個輕類型的操作.比如:
??????? MFnNurbsCurve curveFn;
??????? MObject curve = curveFn.create( ... );
??????? MFnNurbsSurface surface( curve );
???????
??? 這段代碼創建了一個曲線并把它傳給一個曲面操作函數集.既然"MFnNurbsSurface"只能操作表面對象,上面的代碼將什么都不做.但你可能根本不知道.
??? API的錯誤檢測代碼按預置處理這些錯誤.
???
??? 函數集接受任何類型的MObjects對象,如果它們不能識別的話,無論你怎么試著操作他們都會忽略他們并且返回錯誤值.
???
//======================================================================================================================
//======================================================================================================================
??? 命名規則(Naming Conventions)
??? MAYA用前綴來表示它的類類型.
???
??? MFn??????????? 任何使用這個前綴的類是可以操作一個具體"MObjects"類型的函數集.
???
??? MIt??????????? 這是一種迭代器,比函數集更多地和"MObjects"一起.比如"MItCurveCV"被用來操作單獨的"NURBS curve CV"(而不是用"MFnNurbsCurveCV"),
??????????????? 或者迭代所有在曲線上的的CV.
???
??? MPx??????????? 代理類,被設計成用來生成用戶對象類型.
???
??? M??????????? 大部分這種類是一個"Wrappers",比如函數集是操作MAYA的內部對象的,而"MGlobal"是一個靜態方法類,用來操作全局內容,而不需要傳入"MObject".
???
???
//======================================================================================================================
//======================================================================================================================
??? 增加參數
??? 螺旋插件生成一個簡單的曲線,但是它總是輸出同樣的曲線.
???
??? 給曲線例子增加參數.
??? 你可以稍微修改一下代碼,使你可以給曲線指定半徑和傾斜度.修改函數定義,增加參數:
??????? 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 );
???????????????
??? 這段程序讀入參數,這樣你可以用來改變生成的螺旋的半徑和傾斜.這些修改是很簡單的:
??? "for"循環查詢所有的"MArgList"封裝了的參數,兩個"if"段轉換當前的參數(變量"i"來指定訪問)為"MString"(Maya的字符串封裝),然后把他們和兩個
??? 參數標識相比較.
??? 如果匹配,下一個參數轉換成"double"并保存到相應的變量內.比如:
??????? doHelix -p 0.5 -r 5
??? 生成一個半徑5個單位,傾斜為0.5個單位的螺旋.
???
???
//======================================================================================================================
//======================================================================================================================
??? 錯誤檢測
??? 例子已經做了很多的工作了,這時你還沒有做一些錯誤檢測.對于例子這沒什么,不過當制作一個產品級的插件時,你真的需要做檢測錯誤.
???
??? 很多方法最后都帶一個可選的參數.一個指向"MStatus"變量的指針,存放狀態返回值.
???
??? 如果你用以下代碼替代螺旋例子中的參數分析代碼,那么例子將檢查并處理大部分可能的錯誤.
???
??????? // 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"參數可以檢查類型轉換操作是否成功.
???
??? 比如,當索引大于參數個數的時候"args.asString(i, &stat)"可能返回"MS::kFailure".或者,參數不能轉換成"double"的時候,
??? "args.asDouble(++i, &stat)"操作可能會失敗.
???
???
//======================================================================================================================
//======================================================================================================================
??? MStatus 類
??? "MStatus"類可以檢測方法是否失敗.
???
??? 很多API的方法返回一個"MStatus"類的實例,或者把這實例傳回給一個可選的參數."MStatus"類包含了一個"error"方法,和一個被
??? 重載了的操作"bool",如果這實例是包含錯誤狀態的話,以上兩者都會被傳會"false".這意味著你可以很快得檢查一個調用是否正確.
??? 比如:
??????? MStatus status = MGlobal::clearSelectionList();
??????? if (!status) {
??????????? // Do error handling
??????????? ...
??????? }
???????
??? 如果"status"包含錯誤信息的話,你可以做以下幾件事:
???
??????? * 用"statusCode"方法來得到"MStatusCode"的枚舉來指出錯誤的原因.
??????? * 用"errorString"方法來得到一個包含錯誤詳細解釋的"MString".
??????? * 用"perror"方法向標準錯誤輸出錯誤的詳細解釋.或者是你預先提供的信息字符串.
??????? * 用重載了的相等或不相等操作和一個特定的錯誤碼相比較.
??????? * 用"clear"方法重設置實例狀態為成功.
???????
//======================================================================================================================
//======================================================================================================================
??? 錯誤日志
??? 就想使用"MStatus"類一樣,你可以用錯誤日志來檢查API方法的錯誤.
???
??? 有效或無效錯誤日志:
??? 1.在MEL里,用帶"-errlog"標志的"openMayaPref"命令.
??? 2.在插件里,用"MGlobal::startErrorLogging()"和"MGlobal::stopErrorLogging()"方法.
???
??? 一旦你有效了錯誤日志,MAYA生成一個日志文件,每次一個API方法失敗的時候,MAYA將帶有可以顯示哪兒做了調用的小型堆跟蹤的錯誤解釋寫入日志文件.
??? 默認的文件是在當前目錄中的"OpenMayaErrorLog"文件.這也是可以被修改的,如下:
??????? MGlobal::setErrorLogPathName().
???????
??? 提示:
??? 插件也可以使用"MGlobal::doErrorLogEntry()"方法來把它們自己的錯誤信息加入到錯誤日志中.
?? 總覽
??? 一個命令總是用來得到選擇表中的輸入內容."MGlobal::getActiveSelectionList()"方法的結果包含了所有的選擇了的對象,可以
??? 很簡便地使用"MSelectionList "和"MItSelectionList"來檢查.這兩個API也可以被用來編輯選擇列表.
//================================================================================
//================================================================================
??? 一個全局的當前選擇表可以通過"MGlobal::getActiveSelectionList()"得到一個"MSelectionList"的拷貝.
??? 除非你使用"MGlobal::setActiveSelectionList()",任何你作用于"MSelectionList"的修改都不會影響全局的選擇表.
???
??? 你也可以用"MSelectionList"創建你自己的選擇表,并和其他表進行合并.包括全局表.你也可以用這個表來創建對象集.
???
//=================================================================================
//=================================================================================
??? MSelectionList
??? "MSelectionList"提供了讓你可以從列表內增加或者刪除對象的方法.就像在表里遍歷對象一樣.
???
??? 比如,以下插件代碼打印所有已選擇的DAG節點的名字.如果你生成一個幾何體,然后選擇它,這個插件會打印每一個選擇了的對象的名字.
???
??????? #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"內的"setObject()"方法是繼承自"MFnBase"的所有功能,用來設置當前函數集要操作的對象.一般可以通過函數集的構造
??? 方法來做,但是如果函數集已經被創造了,或者你想改變想要操作的對象的時候,你可以用"setObject()".這比你每次需要的時候構造
??? 析構函數集要有效.
???
??? MAYA的選擇構架單一化對象組件的選擇就像"CVs"之類.父對象被放進表內,組件被組織在一起成為一個組,而不是把每個組件都放到表里.
??? 比如,如果"nurbSphereShape1"上的幾個"CVs"被選擇了,上面代碼中"list.getDagPath()"的調用將返回一個指向"nurbSphereShape1"的"MDagPath"
??? 和一個包含了所有的已選"CVs"的"MObject".
???
??? 如果你一直選擇同一個物體中的一部分,那么這個物體只在選擇表中出現一次.而如果你在一個物體上選擇了一些組件,然后在另外的物體上
??? 選擇一些,然后在第一個物體上再選擇一部分,那第一個物體會在表中出現兩次.這樣你可以通過表來檢測物體選擇的順序.
//===================================================================================
//===================================================================================
??? MItSelectionList
??? "MItSelectionList"是一個包含了已選物體的封裝類.既可以是全局選擇表的一個拷貝,也可以是你自己創建的一個表.
???
??? "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"來遍歷表.其效果和之前一樣.
???
??? 你可以簡單地修改代碼,使之能選擇特定的類型,比如,修改迭代器的構造函數為:
??????? MItSelectionList listIter( list, MFn::kNurbsSurface )
???
??? 那么循環只能選擇"NURB"面 -- 它也會忽略"surface CVs".當然,如果你想得到選擇了的"surface CVs",你可以這樣修改:
??????? MItSelectionList listIter( list, MFn::kSurfaceCVComponent )
???
??? 這只會得到已選的"CVs".
???
???
//==================================================================================
//==================================================================================
??? MFn::Type enumeration
??? "MFn::Type enumeration"在整個API里都被使用,用來標識對象類型.
??????? * 函數集都有一個"apiType()"方法,可以用來檢測"MObject"所指向的對象類型.每個函數集都有一個"type()"方法可以用來檢測函數集的類型.
??????? * "MGlobal::getFunctionSetList()"可以返回一個字符串數組來顯示可以接受指定對象的函數集類型.
//==================================================================================
//==================================================================================
??? MGlobal::selectByName()
??? "MSelectionList"里的"add()"方法和"MGlobal::setActiveSelectionList()"聯合使用.提供了一個插件用來修改當前選擇列表的方法.
???
??? 另外一個方法是使用"MGlobal::selectByName()".這會找到所有符合匹配的對象,并添加他們到當前選擇表中.比如:
??????? MGlobal::selectByName( “*Sphere*” );
??? 選擇所有名字中有"Sphere"的物體.
???
??? 提示:
??? 你也可以用"MGlobal::select()"來添加對象到當前選擇列表,而不需要創建"MSelectionList ".