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 ".