Dependency Graph
Dirty Propagation
Push & Pull Mechanism
Lazy Evaluation
1. Dirty Propagation
Dependency Graph Node

由有关联的输入、输出和对应的计算函数组成
输入节点传播到对应的输出节点(Dirty Propagation),直到叶节点
Updation Request(对节点属性产生影响的操作)
- View Port
- Attribute Editor
- Channel Box
- getAttr
反向传播
Clean Propagation
(不会对没有输出要求的节点进行Clean)
注意涂色的是Attribute/Plug,而不是Node本身
总结:
Dirty Propagation向一个方向传播直到叶节点,当出现Updation Request时,传播开始返回并检查哪些节点是Dirty的,最后到达Dirty的根节点时开始计算,设置Attribute/Plug为Clean
2. Push & Pull Mechanism
在Dirty Propagation中,Dirty的标记被push至一个方向直到最后(Pushed Dirty Message)。
3. Lazy Evaluation
在Clean Propagation中会存在依然Dirty的节点。
Maya只更新或执行请求过的属性。
4. Writing Dependency Graph/ Custom Node
4.1 Dependency Graph Node
可以执行计算(DG-Node+Computation)
- DG-Node
- Attribute(任何输入/输出)
- Data Block
- Specialize Handle(Data Handle)
- 保存节点所有数据
4.2 建立一个DG-Node Graph
建立一个DG-Node Graph和建立一个Maya command是很相似的
command
- class PluginCommand
- cmdCreators
- initializePlugin
- uninitializePlugin
DG-Node
class WheelNode
Creator function
initialize function
initializePlugin
uninitializePlugin
在这个案例中,我们会写一个插件,能够让一个小车(两个圆柱和一个平板组成),空间位置发生变化的时候,轮子也发生对应的旋转。
$$
rotate = \frac{translate}{2\pi r}*(-360)
$$
Node Design

4.3 完整流程

1 2 3 4
| from maya import cmds cmds.loadPlugin(r"C:\Users\XZYW\文档\maya\2023\zh_CN\scripts\WheelNode.py")
cmds.createNode("WheelNode")
|
来贴个官网上找到的案例
Maya 帮助 | Python API 2.0 Reference: python/api1/py1CircleNode.py | Autodesk
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
| import sys import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx
nodeName = "WheelNode" nodeId = OpenMaya.MTypeId(0x0008004c)
class WheelNode(OpenMayaMPx.MPxNode): inRadius = OpenMaya.MObject() inTranslate = OpenMaya.MObject() outRotate = OpenMaya.MObject() def __init__(self): OpenMayaMPx.MPxNode.__init__(self) def compute(self, plug, dataBlock): ''' rotate = translate / (2* 3.1416 * radius) * (-360) ''' if plug == WheelNode.outRotate: dataHandleRadius = dataBlock.inputValue(WheelNode.inRadius) dataHandleTranslate = dataBlock.inputValue(WheelNode.inTranslate) inRadiusVal = dataHandleRadius.asFloat() inTranslateVal = dataHandleTranslate.asFloat() outRotateVal = float(inTranslateVal) / float(2 * 3.1416 * inRadiusVal) * (-360) dataHandleRotate = dataBlock.outputValue(WheelNode.outRotate) dataHandleRotate.setFloat(outRotateVal) dataBlock.setClean(plug) else: return OpenMaya.kUnknownParameter def nodeCreator(): return OpenMayaMPx.asMPxPtr(WheelNode())
def nodeInitializer(): mFnAttr = OpenMaya.MFnNumericAttribute() WheelNode.inRadius = mFnAttr.create("radius", "r", OpenMaya.MFnNumericData.kFloat, 0.0) mFnAttr.setReadable(1) mFnAttr.setWritable(1) mFnAttr.setStorable(1) mFnAttr.setKeyable(1) WheelNode.inTranslate = mFnAttr.create("translate", "t", OpenMaya.MFnNumericData.kFloat, 0.0) mFnAttr.setReadable(1) mFnAttr.setWritable(1) mFnAttr.setStorable(1) mFnAttr.setKeyable(1) WheelNode.outRotate = mFnAttr.create("rotate", "rot", OpenMaya.MFnNumericData.kFloat) mFnAttr.setReadable(1) mFnAttr.setWritable(0) mFnAttr.setStorable(0) mFnAttr.setKeyable(0) WheelNode.addAttribute(WheelNode.inRadius) WheelNode.addAttribute(WheelNode.inTranslate) WheelNode.addAttribute(WheelNode.outRotate) WheelNode.attributeAffects(WheelNode.inRadius, WheelNode.outRotate) WheelNode.attributeAffects(WheelNode.inTranslate, WheelNode.outRotate)
def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerNode(nodeName, nodeId, nodeCreator, nodeInitializer) except: sys.stderr.write("Failed to register node:" + nodeName) def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterNode(nodeId) except: sys.stderr.write("Failed to deregister node" + nodeName)
|