【笔记】【Maya工具】Python For Maya(OpenMaya)(二)Dependency Graph

Dependency Graph

  • Dirty Propagation

  • Push & Pull Mechanism

  • Lazy Evaluation

image-20220704094816836

1. Dirty Propagation

Dependency Graph Node

image-20220704095016592

由有关联的输入、输出和对应的计算函数组成

image-20220704095141685

输入节点传播到对应的输出节点(Dirty Propagation),直到叶节点

Updation Request(对节点属性产生影响的操作)

  • View Port
  • Attribute Editor
  • Channel Box
  • getAttr

反向传播

image-20220704095445679

Clean Propagation

(不会对没有输出要求的节点进行Clean)

image-20220704095707170

注意涂色的是Attribute/Plug,而不是Node本身

总结:

Dirty Propagation向一个方向传播直到叶节点,当出现Updation Request时,传播开始返回并检查哪些节点是Dirty的,最后到达Dirty的根节点时开始计算,设置Attribute/Plug为Clean

2. Push & Pull Mechanism

在Dirty Propagation中,Dirty的标记被push至一个方向直到最后(Pushed Dirty Message)。

image-20220704100117924

3. Lazy Evaluation

在Clean Propagation中会存在依然Dirty的节点。

Maya只更新或执行请求过的属性。

4. Writing Dependency Graph/ Custom Node

4.1 Dependency Graph Node

可以执行计算(DG-Node+Computation)

  • DG-Node
    • Attribute(任何输入/输出)
      • Specialize Handle(Plug
    • 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

      • _init_
      • doIt compute
    • Creator function

    • initialize function

      • 初始化节点所有属性

        • MFn-Attribute使用函数集来创建属性

        • create Attribute(Create + set Properties)

          • MFn->create attribute return mObj Handle

          • set Properties

            1. readable->source(输出节点只可读)

            2. writable->destination[setAttr]

            3. Storable->store with file(input)

            4. Keyable ->can be keyed or not

        • attach Attribute to the Node

        • Design circuitry

    • initializePlugin

    • uninitializePlugin

在这个案例中,我们会写一个插件,能够让一个小车(两个圆柱和一个平板组成),空间位置发生变化的时候,轮子也发生对应的旋转。
$$
rotate = \frac{translate}{2\pi r}*(-360)
$$
Node Design

image-20220704102307567

4.3 完整流程

image-20220704112229490

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
# -*- coding: utf-8 -*-  
import sys
import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx


nodeName = "WheelNode"
nodeId = OpenMaya.MTypeId(0x0008004c)# Id是唯一的,定义一个唯一的节点

class WheelNode(OpenMayaMPx.MPxNode):# 继承依赖关系图的类
inRadius = OpenMaya.MObject()# 用于储存创建属性时mFn函数集返回的mObj
inTranslate = OpenMaya.MObject()
outRotate = OpenMaya.MObject()

def __init__(self):
OpenMayaMPx.MPxNode.__init__(self)

def compute(self, plug, dataBlock):# 只要输入节点发生改变,maya就会调用compute函数,并且会
# 发送outputNode,以及输入数据的数据块
'''
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)

# 结束计算,设置clean
dataBlock.setClean(plug)

else:
return OpenMaya.kUnknownParameter

def nodeCreator():
return OpenMayaMPx.asMPxPtr(WheelNode())

def nodeInitializer():
# 1.创建一个Function set for numeric attribute
mFnAttr = OpenMaya.MFnNumericAttribute()

# 2.创建属性
# Input Radius
WheelNode.inRadius = mFnAttr.create("radius", "r",
OpenMaya.MFnNumericData.kFloat, 0.0)# longname, shortname,attrType,defaultValue

# set properties
mFnAttr.setReadable(1)# bool
mFnAttr.setWritable(1)
mFnAttr.setStorable(1)
mFnAttr.setKeyable(1)
# Input Translate
WheelNode.inTranslate = mFnAttr.create("translate", "t",
OpenMaya.MFnNumericData.kFloat, 0.0)
mFnAttr.setReadable(1)# bool
mFnAttr.setWritable(1)
mFnAttr.setStorable(1)
mFnAttr.setKeyable(1)
# Output Rotation
WheelNode.outRotate = mFnAttr.create("rotate", "rot",
OpenMaya.MFnNumericData.kFloat)#输出值是计算的,不用设默认值
mFnAttr.setReadable(1)
mFnAttr.setWritable(0)
mFnAttr.setStorable(0)
mFnAttr.setKeyable(0)

# 3.attach Attribute to the Node
WheelNode.addAttribute(WheelNode.inRadius)
WheelNode.addAttribute(WheelNode.inTranslate)
WheelNode.addAttribute(WheelNode.outRotate)

# 4.Design the circuitry如何让maya知道节点之间的关系
WheelNode.attributeAffects(WheelNode.inRadius, WheelNode.outRotate)# input,output
WheelNode.attributeAffects(WheelNode.inTranslate, WheelNode.outRotate)


# 初始化,和maya pluginCommand是一样的
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)