前言
在插件(三)中,我们使用了自定义的Locator结点,它也是个DG Node,本文目的是学习和理解Mplug && Attribute。
MyDGNode是我们自定义的结点, 有输入、输出Attribute,下图是一个用法:
将时间结点time1的输出-->MyDGNode1-->sphere1(Transform结点).
MyDGNode的实现
从MPxNode继承。MyDGNode.h
#ifndef __MYDGNODE_H__ #define __MYDGNODE_H__ #ifdef WIN32 #ifdef NT_PLUGIN #define NT_PLUGIN #endif #endif #include #include #include #include #include #include #include #include #include #include #include #include #include /// MyDGNode class MyDGNode : public MPxNode { public: MyDGNode(); virtual ~MyDGNode(); /// /brief /// to calculate the value of a specific output attribute. virtual MStatus compute(const MPlug &outPlug, MDataBlock &dataBlock); /// /brief /// create this-self static void *creator(); /// /brief /// initialize the node, to append the addtional attributes. static MStatus initialize(); public: const static MTypeId m_typeId; const static MString m_typeName; private: static MObject m_inTime; /// attribute inTime for in static MObject m_outValue; /// attribute outValue to out }; #endif /// __MYDGNODE_H__
1. virtual MStatus compute(const MPlug &outPlug, MDataBlock &dataBlock);
当DG网络出现脏数据时,该函数将被调用,用于更新数据.
2. static MStatus initialize();
初始化该结点,创建Attributes(相当于动态添加类成员变量).
3. static MObject m_inTime; static MObject m_outValue;
新的Attribute标识符(句柄).
实现代码MyDGNode.cpp
#include "MyDGNode.h" #include #include const MTypeId MyDGNode::m_typeId = 0x10001; const MString MyDGNode::m_typeName = "MyDGNode"; MObject MyDGNode::m_inTime; MObject MyDGNode::m_outValue; /// construction && destruction MyDGNode::MyDGNode() { std::cout << "MyDGNode()" << std::endl; } MyDGNode::~MyDGNode() { std::cout << "~MyDGNode()" << std::endl; } void *MyDGNode::creator() { std::cout << "MyDGNode::creator()" << std::endl; return new MyDGNode(); } MStatus MyDGNode::initialize() { /// attribute "time" 将连接到全局时间结点的attribute上 MFnUnitAttribute uAttr; m_inTime = uAttr.create("time", "t", MFnUnitAttribute::kTime); uAttr.setStorable(false); uAttr.setKeyable(false); MFnNumericAttribute nAttr; m_outValue = nAttr.create("output", "o", MFnNumericData::kFloat, 0.0f); nAttr.setReadable(true); nAttr.setKeyable(false); // 必须为false,否则compute将不会被调用,不明白. addAttribute(m_inTime); addAttribute(m_outValue); /// 设置依赖 attributeAffects(m_inTime, m_outValue); return MS::kSuccess; } MStatus MyDGNode::compute(const MPlug &plug, MDataBlock &data) { std::cout << "MyDGNode::compute() begin " << std::endl; if (plug != m_outValue) return MS::kUnknownParameter; /// 获取inTime MDataHandle timeData = data.inputValue(m_inTime); MDataHandle outData = data.outputValue(m_outValue); MTime time = timeData.asTime(); std::cout << "time.as(MTime::kSeconds): " << time.as(MTime::kSeconds) << std::endl; outData.set((float)sin(time.as(MTime::kSeconds))); data.setClean(plug); return MS::kSuccess; }
注册MyDGNode, pluginMain.cpp
#include #include #include "MyDGNode.h" #ifdef WIN32 #define MLL_EXPORT __declspec(dllexport) #else #define MLL_EXPORT #endif MLL_EXPORT MStatus initializePlugin(MObject obj) { std::cout << "initializePlugin" << std::endl; MStatus status; MFnPlugin plugin(obj, "Jett Huang", "1.0", "Any"); status = plugin.registerNode(MyDGNode::m_typeName, MyDGNode::m_typeId, MyDGNode::creator, MyDGNode::initialize, MPxNode::kDependNode); return status; } MLL_EXPORT MStatus uninitializePlugin(MObject obj) { std::cout << "uninitializePlugin" << std::endl; MStatus status; MFnPlugin plugin(obj); status = plugin.deregisterNode(MyDGNode::m_typeId); return status; }
Attribute Editor模板MEL
/// /brief /// Attribute Editor Template. /// /// /// global proc AEMyDGNodeTemplate ( string $nodeName ) { print("DEBUG: AEMyDGNodeTemplate is Invokded: " + $nodeName); editorTemplate -beginScrollLayout; // 加入我们的属性编辑控件 editorTemplate -beginLayout "MyDGNode Input" -collapse 0; editorTemplate -addControl "time"; editorTemplate -endLayout; AEdependNodeTemplate $nodeName; // This will add the standard UI controls for the node editorTemplate -addExtraControls; editorTemplate -endScrollLayout; }
放在Maya用户目录的Scripts下面。
编译工程.....
加载插件后,在MEL窗口中执行如下脚本
// run this MEL to test the MyDGNode
{
$myNode = `createNode "MyDGNode"`;
// create a polygon sphere
string $psphere[] = `polySphere -r 1 -sx 20 -sy 20 -ax 0 1 0 -tx 1 -ch 1`;
// connect the output of the node to the x-scale of the ploy sphere
string $plugName = `connectAttr ($myNode + ".output") ($psphere[0] + ".sx")`;
print $plugName;
print("/n");
// connect the time1 output to the "time" of myNode
$plugName = `connectAttr "time1.outTime" ($myNode + ".time")`;
print $plugName;
print("/n");
}
然后开启时间滑块,你会发现球体的缩放动画。
做个实验
在MEL命令中继续输入如下命令:
connectAttr "time1.outTime" "MyDGNode1.output";
直接将time1连接到MyDGNode1的ouput, 发现对显示无影响,看看连接图如下:
如果输入的命令是:
connectAttr "pSphere1.sy" "MyDGNode1.time";
将出现错误, Error: line 1: 'MyDGNode1.time' already has an incoming connection from 'time1.outTime'.
说明incoming的来源只能是一个!