MAYA插件入门 之三(转载)
halfScaleNodeNode.cpp
- //
- // Copyright (C)
- //
- // File: halfScaleNodeNode.cpp
- //
- // Dependency Graph Node: halfScaleNode
- //
- // Author: Maya Plug-in Wizard 2.0
- //
- #include "halfScaleNodeNode.h"
- #include
- #include
- #include
- #include
- // 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( 0x02010 );
- // Example attributes
- //
- MObject halfScaleNode::input;
- MObject halfScaleNode::output;
- halfScaleNode::halfScaleNode() {}
- halfScaleNode::~halfScaleNode() {}
- MStatus halfScaleNode::compute( const MPlug& plug, MDataBlock& data )
- //
- // Description:
- // This method computes the value of the given output plug based
- // on the values of the input attributes.
- //
- // Arguments:
- // plug - the plug to compute
- // data - object that provides access to the attributes for this node
- //
- {
- MStatus returnStatus;
- // Check which output attribute we have been asked to compute. If this
- // node doesn't know how to compute it, we must return
- // MS::kUnknownParameter.
- //
- if( plug == output )
- {
- // Get a handle to the input attribute that we will need for the
- // computation. If the value is being supplied via a connection
- // in the dependency graph, then this call will cause all upstream
- // connections to be evaluated so that the correct value is supplied.
- //
- MDataHandle inputData = data.inputValue( input, &returnStatus );
- if( returnStatus != MS::kSuccess )
- MGlobal::displayError( "Node halfScaleNode cannot get value\n" );
- else
- {
- // Read the input value from the handle.
- //
- float result = inputData.asFloat();
- result *= 0.5;
- // Get a handle to the output attribute. This is similar to the
- // "inputValue" call above except that no dependency graph
- // computation will be done as a result of this call.
- //
- MDataHandle outputHandle = data.outputValue( halfScaleNode::output );
- // This just copies the input value through to the output.
- //
- outputHandle.set( result );
- // Mark the destination plug as being clean. This will prevent the
- // dependency graph from repeating this calculation until an input
- // of this node changes.
- //
- data.setClean(plug);
- }
- } else {
- return MS::kUnknownParameter;
- }
- return MS::kSuccess;
- }
- void* halfScaleNode::creator()
- //
- // Description:
- // this method exists to give Maya a way to create new objects
- // of this type.
- //
- // Return Value:
- // a new object of this type
- //
- {
- return new halfScaleNode();
- }
- MStatus halfScaleNode::initialize()
- //
- // Description:
- // This method is called to create and initialize all of the attributes
- // and attribute dependencies for this node type. This is only called
- // once when the node type is registered with Maya.
- //
- // Return Values:
- // MS::kSuccess
- // MS::kFailure
- //
- {
- // This sample creates a single input float attribute and a single
- // output float attribute.
- //
- MFnNumericAttribute nAttr;
- MStatus stat;
- input = nAttr.create( "input", "in", MFnNumericData::kFloat, 0.0 );
- // Attribute will be written to files when this type of node is stored
- nAttr.setStorable(true);
- // Attribute is keyable and will show up in the channel box
- nAttr.setKeyable(true);
- output = nAttr.create( "output", "out", MFnNumericData::kFloat, 0.0 );
- // Attribute is read-only because it is an output attribute
- nAttr.setWritable(false);
- // Attribute will not be written to files when this type of node is stored
- nAttr.setStorable(false);
- // Add the attributes we have created to the node
- //
- stat = addAttribute( input );
- if (!stat) { stat.perror("addAttribute"); return stat;}
- stat = addAttribute( output );
- if (!stat) { stat.perror("addAttribute"); return stat;}
- // Set up a dependency between the input and the output. This will cause
- // the output to be marked dirty when the input changes. The output will
- // then be recomputed the next time the value of the output is requested.
- //
- stat = attributeAffects( input, output );
- if (!stat) { stat.perror("attributeAffects"); return stat;}
- return MS::kSuccess;
- }
- //
- // Copyright (C)
- //
- // File: halfScaleNodeNode.cpp
- //
- // Dependency Graph Node: halfScaleNode
- //
- // Author: Maya Plug-in Wizard 2.0
- //
- #include "halfScaleNodeNode.h"
- #include
- #include
- #include
- #include
- // 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( 0x02010 );
- // Example attributes
- //
- MObject halfScaleNode::input;
- MObject halfScaleNode::output;
- halfScaleNode::halfScaleNode() {}
- halfScaleNode::~halfScaleNode() {}
- MStatus halfScaleNode::compute( const MPlug& plug, MDataBlock& data )
- //
- // Description:
- // This method computes the value of the given output plug based
- // on the values of the input attributes.
- //
- // Arguments:
- // plug - the plug to compute
- // data - object that provides access to the attributes for this node
- //
- {
- MStatus returnStatus;
- // Check which output attribute we have been asked to compute. If this
- // node doesn't know how to compute it, we must return
- // MS::kUnknownParameter.
- //
- if( plug == output )
- {
- // Get a handle to the input attribute that we will need for the
- // computation. If the value is being supplied via a connection
- // in the dependency graph, then this call will cause all upstream
- // connections to be evaluated so that the correct value is supplied.
- //
- MDataHandle inputData = data.inputValue( input, &returnStatus );
- if( returnStatus != MS::kSuccess )
- MGlobal::displayError( "Node halfScaleNode cannot get value\n" );
- else
- {
- // Read the input value from the handle.
- //
- float result = inputData.asFloat();
- result *= 0.5;
- // Get a handle to the output attribute. This is similar to the
- // "inputValue" call above except that no dependency graph
- // computation will be done as a result of this call.
- //
- MDataHandle outputHandle = data.outputValue( halfScaleNode::output );
- // This just copies the input value through to the output.
- //
- outputHandle.set( result );
- // Mark the destination plug as being clean. This will prevent the
- // dependency graph from repeating this calculation until an input
- // of this node changes.
- //
- data.setClean(plug);
- }
- } else {
- return MS::kUnknownParameter;
- }
- return MS::kSuccess;
- }
- void* halfScaleNode::creator()
- //
- // Description:
- // this method exists to give Maya a way to create new objects
- // of this type.
- //
- // Return Value:
- // a new object of this type
- //
- {
- return new halfScaleNode();
- }
- MStatus halfScaleNode::initialize()
- //
- // Description:
- // This method is called to create and initialize all of the attributes
- // and attribute dependencies for this node type. This is only called
- // once when the node type is registered with Maya.
- //
- // Return Values:
- // MS::kSuccess
- // MS::kFailure
- //
- {
- // This sample creates a single input float attribute and a single
- // output float attribute.
- //
- MFnNumericAttribute nAttr;
- MStatus stat;
- input = nAttr.create( "input", "in", MFnNumericData::kFloat, 0.0 );
- // Attribute will be written to files when this type of node is stored
- nAttr.setStorable(true);
- // Attribute is keyable and will show up in the channel box
- nAttr.setKeyable(true);
- output = nAttr.create( "output", "out", MFnNumericData::kFloat, 0.0 );
- // Attribute is read-only because it is an output attribute
- nAttr.setWritable(false);
- // Attribute will not be written to files when this type of node is stored
- nAttr.setStorable(false);
- // Add the attributes we have created to the node
- //
- stat = addAttribute( input );
- if (!stat) { stat.perror("addAttribute"); return stat;}
- stat = addAttribute( output );
- if (!stat) { stat.perror("addAttribute"); return stat;}
- // Set up a dependency between the input and the output. This will cause
- // the output to be marked dirty when the input changes. The output will
- // then be recomputed the next time the value of the output is requested.
- //
- stat = attributeAffects( input, output );
- if (!stat) { stat.perror("attributeAffects"); return stat;}
- return MS::kSuccess;
- }
我们可以看到,现在的工程代码比刚才的命令插件要复杂多了,除了有对应的halfScaleNode.cpp和halfScaleNode.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.mll的MAYA插件,和前面所说的安装方式一样,我们把halfScaleNode.mll拷贝到plug-in文件夹中,然后在MAYA插件管理器中加载该插件。
我们来验检一下该结点插件是否能正确运行。我们要在maya场景中建两个小球,在命令窗口中输入并运行以下mel代码:
polySphere;
createNode halfScaleNode;
connectAttr halfScaleNode1.output pSphere2.translateX;
从超图上我们可以后清晰地看到,pSphere1的translateX属性被连接到halfScaleNode1的input输入口,经过运算后,输出给pSphere2的translateX属性。现在我们选择pSphere1然后沿X轴平称,我们可以看到,pSphere2会跟随pSphere1一起移动,但总是慢半拍,这正是我们想要的效果。
这样,一个简单的MAYA插件也就完成了。从上面的操作,我们也可以看到,一般一就,单独一个MAYA结点,如果用手工,是很难被正确连接起来的,所以多数情况下,结点插件都会结合mel脚本或API命令来一起使用。
以上,只是简单地介绍了编写MAYA API插件的入门知识,在实际应用中,一个MAYA API插件要比这个复杂得多,一个MAYA结点,它可以包括多个接口,而每个接口可以是各种类型的参数,如,浮点、整型、向量、矩阵等等,甚至可以是一个mesh对像或是一个二维数组。这些,我们都可以在每个结点的initialize()函数中生成和指定。
为了管理上的方便,我们可以在一个MAYA API插件中包含多个结点和命令,也就是说一个mll文件中可能有多个node和command,我们只要把它们都在pluginMain.cpp中的MStatus initializePlugin( MObject obj )函数进行注册就可以了。
有问题可以给我发邮件 [email protected] 欢迎交流。