MAYA插件入门 之三(转载)

halfScaleNodeNode.cpp

 

  1. //   
  2. // Copyright (C)    
  3. //    
  4. // File: halfScaleNodeNode.cpp   
  5. //   
  6. // Dependency Graph Node: halfScaleNode   
  7. //   
  8. // Author: Maya Plug-in Wizard 2.0   
  9. //   
  10.   
  11. #include "halfScaleNodeNode.h"   
  12.   
  13. #include    
  14. #include    
  15. #include    
  16.   
  17. #include    
  18.   
  19. // You MUST change this to a unique value!!!  The id is a 32bit value used   
  20. // to identify this type of node in the binary file format.     
  21. //   
  22. //#error change the following to a unique value and then erase this line    
  23. MTypeId     halfScaleNode::id( 0x02010 );  
  24.   
  25. // Example attributes   
  26. //    
  27. MObject     halfScaleNode::input;          
  28. MObject     halfScaleNode::output;         
  29.   
  30. halfScaleNode::halfScaleNode() {}  
  31. halfScaleNode::~halfScaleNode() {}  
  32.   
  33. MStatus halfScaleNode::compute( const MPlug& plug, MDataBlock& data )  
  34. //   
  35. //  Description:   
  36. //      This method computes the value of the given output plug based   
  37. //      on the values of the input attributes.   
  38. //   
  39. //  Arguments:   
  40. //      plug - the plug to compute   
  41. //      data - object that provides access to the attributes for this node   
  42. //   
  43. {  
  44.     MStatus returnStatus;  
  45.    
  46.     // Check which output attribute we have been asked to compute.  If this    
  47.     // node doesn't know how to compute it, we must return    
  48.     // MS::kUnknownParameter.   
  49.     //    
  50.     if( plug == output )  
  51.     {  
  52.         // Get a handle to the input attribute that we will need for the   
  53.         // computation.  If the value is being supplied via a connection    
  54.         // in the dependency graph, then this call will cause all upstream     
  55.         // connections to be evaluated so that the correct value is supplied.   
  56.         //    
  57.         MDataHandle inputData = data.inputValue( input, &returnStatus );  
  58.   
  59.         if( returnStatus != MS::kSuccess )  
  60.             MGlobal::displayError( "Node halfScaleNode cannot get value\n" );  
  61.         else  
  62.         {  
  63.             // Read the input value from the handle.   
  64.             //   
  65.             float result = inputData.asFloat();  
  66.             result *= 0.5;  
  67.             // Get a handle to the output attribute.  This is similar to the   
  68.             // "inputValue" call above except that no dependency graph    
  69.             // computation will be done as a result of this call.   
  70.             //    
  71.             MDataHandle outputHandle = data.outputValue( halfScaleNode::output );  
  72.             // This just copies the input value through to the output.     
  73.             //    
  74.             outputHandle.set( result );  
  75.             // Mark the destination plug as being clean.  This will prevent the   
  76.             // dependency graph from repeating this calculation until an input    
  77.             // of this node changes.   
  78.             //    
  79.             data.setClean(plug);  
  80.         }  
  81.     } else {  
  82.         return MS::kUnknownParameter;  
  83.     }  
  84.   
  85.     return MS::kSuccess;  
  86. }  
  87.   
  88. void* halfScaleNode::creator()  
  89. //   
  90. //  Description:   
  91. //      this method exists to give Maya a way to create new objects   
  92. //      of this type.    
  93. //   
  94. //  Return Value:   
  95. //      a new object of this type   
  96. //   
  97. {  
  98.     return new halfScaleNode();  
  99. }  
  100.   
  101. MStatus halfScaleNode::initialize()  
  102. //   
  103. //  Description:   
  104. //      This method is called to create and initialize all of the attributes   
  105. //      and attribute dependencies for this node type.  This is only called    
  106. //      once when the node type is registered with Maya.   
  107. //   
  108. //  Return Values:   
  109. //      MS::kSuccess   
  110. //      MS::kFailure   
  111. //         
  112. {  
  113.     // This sample creates a single input float attribute and a single   
  114.     // output float attribute.   
  115.     //   
  116.     MFnNumericAttribute nAttr;  
  117.     MStatus             stat;  
  118.   
  119.     input = nAttr.create( "input""in", MFnNumericData::kFloat, 0.0 );  
  120.     // Attribute will be written to files when this type of node is stored   
  121.     nAttr.setStorable(true);  
  122.     // Attribute is keyable and will show up in the channel box   
  123.     nAttr.setKeyable(true);  
  124.   
  125.     output = nAttr.create( "output""out", MFnNumericData::kFloat, 0.0 );  
  126.     // Attribute is read-only because it is an output attribute   
  127.     nAttr.setWritable(false);  
  128.     // Attribute will not be written to files when this type of node is stored   
  129.     nAttr.setStorable(false);  
  130.   
  131.     // Add the attributes we have created to the node   
  132.     //   
  133.     stat = addAttribute( input );  
  134.         if (!stat) { stat.perror("addAttribute"); return stat;}  
  135.     stat = addAttribute( output );  
  136.         if (!stat) { stat.perror("addAttribute"); return stat;}  
  137.   
  138.     // Set up a dependency between the input and the output.  This will cause   
  139.     // the output to be marked dirty when the input changes.  The output will   
  140.     // then be recomputed the next time the value of the output is requested.   
  141.     //   
  142.     stat = attributeAffects( input, output );  
  143.         if (!stat) { stat.perror("attributeAffects"); return stat;}  
  144.   
  145.     return MS::kSuccess;  
  146.   
  147. }  
  1. //  
  2. // Copyright (C)   
  3. //   
  4. // File: halfScaleNodeNode.cpp  
  5. //  
  6. // Dependency Graph Node: halfScaleNode  
  7. //  
  8. // Author: Maya Plug-in Wizard 2.0  
  9. //  
  10.   
  11. #include "halfScaleNodeNode.h"  
  12.   
  13. #include   
  14. #include   
  15. #include   
  16.   
  17. #include   
  18.   
  19. // You MUST change this to a unique value!!!  The id is a 32bit value used  
  20. // to identify this type of node in the binary file format.    
  21. //  
  22. //#error change the following to a unique value and then erase this line   
  23. MTypeId     halfScaleNode::id( 0x02010 );  
  24.   
  25. // Example attributes  
  26. //   
  27. MObject     halfScaleNode::input;          
  28. MObject     halfScaleNode::output;         
  29.   
  30. halfScaleNode::halfScaleNode() {}  
  31. halfScaleNode::~halfScaleNode() {}  
  32.   
  33. MStatus halfScaleNode::compute( const MPlug& plug, MDataBlock& data )  
  34. //  
  35. //  Description:  
  36. //      This method computes the value of the given output plug based  
  37. //      on the values of the input attributes.  
  38. //  
  39. //  Arguments:  
  40. //      plug - the plug to compute  
  41. //      data - object that provides access to the attributes for this node  
  42. //  
  43. {  
  44.     MStatus returnStatus;  
  45.    
  46.     // Check which output attribute we have been asked to compute.  If this   
  47.     // node doesn't know how to compute it, we must return   
  48.     // MS::kUnknownParameter.  
  49.     //   
  50.     if( plug == output )  
  51.     {  
  52.         // Get a handle to the input attribute that we will need for the  
  53.         // computation.  If the value is being supplied via a connection   
  54.         // in the dependency graph, then this call will cause all upstream    
  55.         // connections to be evaluated so that the correct value is supplied.  
  56.         //   
  57.         MDataHandle inputData = data.inputValue( input, &returnStatus );  
  58.   
  59.         if( returnStatus != MS::kSuccess )  
  60.             MGlobal::displayError( "Node halfScaleNode cannot get value\n" );  
  61.         else  
  62.         {  
  63.             // Read the input value from the handle.  
  64.             //  
  65.             float result = inputData.asFloat();  
  66.             result *= 0.5;  
  67.             // Get a handle to the output attribute.  This is similar to the  
  68.             // "inputValue" call above except that no dependency graph   
  69.             // computation will be done as a result of this call.  
  70.             //   
  71.             MDataHandle outputHandle = data.outputValue( halfScaleNode::output );  
  72.             // This just copies the input value through to the output.    
  73.             //   
  74.             outputHandle.set( result );  
  75.             // Mark the destination plug as being clean.  This will prevent the  
  76.             // dependency graph from repeating this calculation until an input   
  77.             // of this node changes.  
  78.             //   
  79.             data.setClean(plug);  
  80.         }  
  81.     } else {  
  82.         return MS::kUnknownParameter;  
  83.     }  
  84.   
  85.     return MS::kSuccess;  
  86. }  
  87.   
  88. void* halfScaleNode::creator()  
  89. //  
  90. //  Description:  
  91. //      this method exists to give Maya a way to create new objects  
  92. //      of this type.   
  93. //  
  94. //  Return Value:  
  95. //      a new object of this type  
  96. //  
  97. {  
  98.     return new halfScaleNode();  
  99. }  
  100.   
  101. MStatus halfScaleNode::initialize()  
  102. //  
  103. //  Description:  
  104. //      This method is called to create and initialize all of the attributes  
  105. //      and attribute dependencies for this node type.  This is only called   
  106. //      once when the node type is registered with Maya.  
  107. //  
  108. //  Return Values:  
  109. //      MS::kSuccess  
  110. //      MS::kFailure  
  111. //        
  112. {  
  113.     // This sample creates a single input float attribute and a single  
  114.     // output float attribute.  
  115.     //  
  116.     MFnNumericAttribute nAttr;  
  117.     MStatus             stat;  
  118.   
  119.     input = nAttr.create( "input""in", MFnNumericData::kFloat, 0.0 );  
  120.     // Attribute will be written to files when this type of node is stored  
  121.     nAttr.setStorable(true);  
  122.     // Attribute is keyable and will show up in the channel box  
  123.     nAttr.setKeyable(true);  
  124.   
  125.     output = nAttr.create( "output""out", MFnNumericData::kFloat, 0.0 );  
  126.     // Attribute is read-only because it is an output attribute  
  127.     nAttr.setWritable(false);  
  128.     // Attribute will not be written to files when this type of node is stored  
  129.     nAttr.setStorable(false);  
  130.   
  131.     // Add the attributes we have created to the node  
  132.     //  
  133.     stat = addAttribute( input );  
  134.         if (!stat) { stat.perror("addAttribute"); return stat;}  
  135.     stat = addAttribute( output );  
  136.         if (!stat) { stat.perror("addAttribute"); return stat;}  
  137.   
  138.     // Set up a dependency between the input and the output.  This will cause  
  139.     // the output to be marked dirty when the input changes.  The output will  
  140.     // then be recomputed the next time the value of the output is requested.  
  141.     //  
  142.     stat = attributeAffects( input, output );  
  143.         if (!stat) { stat.perror("attributeAffects"); return stat;}  
  144.   
  145.     return MS::kSuccess;  
  146.   
  147. }  


 

 

我们可以看到,现在的工程代码比刚才的命令插件要复杂多了,除了有对应的halfScaleNode.cpphalfScaleNode.h文件之外,还有一个pluginMain.cpp文件,这是每个MAYA插件的入口,MAYA在加载该结点的时候,会自动运行initializePlugin( MObject obj )函数,因此我们就可以在这里做一些初始化的操作,其中最重要的就是要注册这个maya结点。

status = plugin.registerNode( "halfScaleNode", halfScaleNode::id, halfScaleNode::creator,

                                       halfScaleNode::initialize );

if (!status) {

     status.perror("registerNode");

     return status;

}

所有自定义的maya结点及命令,都必须在初始化的时候注册,才能被MAYA识别和使用。注册的时候我们要注意的是,新的结点名和结点ID不能与已有的结点冲突,也就是说结点名和结点ID在整个MAYA系统中都必须是唯一的。所以在halfScaleNodeNode.cpp文件的开始有这样一个定义结点ID的代码

// You MUST change this to a unique value!!!  The id is a 32bit value used

// to identify this type of node in the binary file format. 

#error change the following to a unique value and then erase this line

MTypeId     halfScaleNode::id( 0x00001 );

这里就提示我们必须要给该结点分配一个唯一的ID,要不就没法通过编译。我们可以把以上代码改为

//#error change the following to a unique value and then erase this line

MTypeId     halfScaleNode::id( 0x02010 );

这样我们就可以正常地编译代码了。

 

接下来我们来详细说一下每个结点的核心运算函数:compute( const MPlug& plug, MDataBlock& data );前面我们说过,一个结点是由输入接口、输出接口及运算核心组成,这里的运算核心就是compute()函数,而输入输出接口则被封装在MDataBlock& data这个对像里面,我们通过相应的函数,就可以取得输入口和输出口所对应的地址,然后对这些数据进行操作:

MDataHandle inputData = data.inputValue( input, &returnStatus );

MDataHandle outputHandle = data.outputValue( halfScaleNode::output );

 

float result = inputData.asFloat();

这里,result所得到的就是输入数据的原始值,如果我们不作任何运算,直接把它赋值给输出接口

outputHandle.set( result );

那么得到的输出结果,也不会有任何改变。现在我们把输入数据乘以0.5然后再赋给输出接口:

float result = inputData.asFloat();

result = result * 0.5;

outputHandle.set( result );

很容易地,我们就达到了我们所想要实现的功能。把工程编译一下,得到一个叫halfScaleNode.mllMAYA插件,和前面所说的安装方式一样,我们把halfScaleNode.mll拷贝到plug-in文件夹中,然后在MAYA插件管理器中加载该插件。

我们来验检一下该结点插件是否能正确运行。我们要在maya场景中建两个小球,在命令窗口中输入并运行以下mel代码:

polySphere;

createNode halfScaleNode;

connectAttr halfScaleNode1.output pSphere2.translateX;

MAYA插件入门 之三(转载)MAYA插件入门 之三(转载)

 

MAYA插件入门 之三(转载)

从超图上我们可以后清晰地看到,pSphere1translateX属性被连接到halfScaleNode1input输入口,经过运算后,输出给pSphere2translateX属性。现在我们选择pSphere1然后沿X轴平称,我们可以看到,pSphere2会跟随pSphere1一起移动,但总是慢半拍,这正是我们想要的效果。

     这样,一个简单的MAYA插件也就完成了。从上面的操作,我们也可以看到,一般一就,单独一个MAYA结点,如果用手工,是很难被正确连接起来的,所以多数情况下,结点插件都会结合mel脚本或API命令来一起使用。

     以上,只是简单地介绍了编写MAYA API插件的入门知识,在实际应用中,一个MAYA API插件要比这个复杂得多,一个MAYA结点,它可以包括多个接口,而每个接口可以是各种类型的参数,如,浮点、整型、向量、矩阵等等,甚至可以是一个mesh对像或是一个二维数组。这些,我们都可以在每个结点的initialize()函数中生成和指定。

     为了管理上的方便,我们可以在一个MAYA API插件中包含多个结点和命令,也就是说一个mll文件中可能有多个nodecommand,我们只要把它们都在pluginMain.cpp中的MStatus initializePlugin( MObject obj )函数进行注册就可以了。

有问题可以给我发邮件 [email protected] 欢迎交流。