【笔记】【maya工具】Python For Maya(OpenMaya)(三)Structure of a Deformer

这个案例最终复现失败了,还是因为教程太老了,版本对不上,有很多api已经有了很大的变化

1. Deformer

是一个DG node

有一个或多个几何节点作为输入

通过某种算法得到结果

  • DG

    • 空结点
    • 添加属性(IO)
    • 设计circuitry
    • 添加计算函数
  • Deformer Node

    • Input(function)
      • input
        • gourpId,inputGeometry
      • weight
      • envelope
    • output
      • outputGeometry
    • Predefined Compute()
      • deform(args) {}
  • Create Deformer Node

    • Creator()
    • initialize()
    • initializePlugin()
    • uninitializePlugin()
    • class
      • _init_()
      • compute() ==deform()==

2. Writing Deformer / DeformerNode

1
2
3
import maya.cmds as cmds
cmds.loadPlugin(r'ripple.py')
cmds.deformer(type = "RippleDeformer")

2.1 attributes

Amplitude(0-1)

Displace(0-10)

maya的默认属性设置是

  • Readable
  • Writable
  • Connectable
  • Storable
  • Cached
  • Not arrays
  • Not Keyable
  • Not hidden
  • 。。。
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import math
import sys

import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx

nodeName = "RippleDeformer"
nodeID = OpenMaya.MTypeId(0x102fff)


class Ripple(OpenMayaMPx.MPxDeformerNode):
'''
Commands ----> MPxCommand
Custom ----> MPxNode
Deformer ----> MPxDeformerNode
'''

mObj_Amplitude = OpenMaya.MObject()
mObj_Displace = OpenMaya.MObject()

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

def deform(self, dataBlock, geoIterator, matrix, geometryIndex):
# 1.attach handle to array value
# 2.jump to Element
# 3.data Handle will reach to specific dataBlock
# 4.child -> inputGeom
input = OpenMayaMPx.cvar.MPxGeometryFilter_input
# 1.Attach a handle to input Array Attribute
# 理解为列表,返回头指针
dataHandleInputArray = dataBlock.inputArrayValue(input)
# 2.Jump to particular element
# 查询到对应的列表元素
dataHandleInputArray.jumpToElement(geometryIndex)
# 3.Attach a handle to specific dataBlock
# 取出该指针下列表元素的储存的内容
dataHandleInputElement = dataHandleInputArray.inputValue()
# 4.Reach to the child - inputGeom
# 找到该顶点对应属性
inputGeom = OpenMayaMPx.cvar.MPxGeometryFilter_inputGeom
dataHandleInputGeom = dataHandleInputElement.child(inputGeom)
inMesh = dataHandleInputGeom.asMesh()
# 开始计算了
# Envelope
# #deform混合程度
envelope = OpenMayaMPx.cvar.MPxGeometryFilter_envelope
dataHandleEnvelope = dataBlock.inputValue(envelope)
envelopeValue = dataHandleEnvelope.asFloat()
# Amplitude
dataHandleAmplitude = dataBlock.inputValue(Ripple.mObj_Amplitude)
amplitudeValue = dataHandleAmplitude.asFloat()
# Displace
dataHandleDisplace = dataBlock.inputValue(Ripple.mObj_Displace)
displaceValue = dataHandleDisplace.asFloat()

mFloatVectorArray_normal = OpenMaya.MFloatVectorArray()
mFnMesh = OpenMaya.MFnMesh(inMesh)
mFnMesh.getVertexNormals(False, mFloatVectorArray_normal, OpenMaya.MSpace.kObject)# angleWeighted,output,物体空间法线

# Geometry iterator遍历几何元素
while(not geoIterator.isDone()):

pointPosition = geoIterator.position()

pointPosition.x = pointPosition.x + math.sin(geoIterator.index() + displaceValue) * amplitudeValue * mFloatVectorArray_normal[geoIterator.index()].x * envelopeValue
pointPosition.y = pointPosition.y + math.sin(geoIterator.index() + displaceValue) * amplitudeValue * mFloatVectorArray_normal[geoIterator.index()].y * envelopeValue
pointPosition.z = pointPosition.z + math.sin(geoIterator.index() + displaceValue) * amplitudeValue * mFloatVectorArray_normal[geoIterator.index()].z * envelopeValue

geoIterator.setPosition(pointPosition)

geoIterator.next()




def deformerCreator():
nodePtr = OpenMayaMPx.asMPxPtr(Ripple())
return nodePtr

def nodeInitializer():
'''
Create Attributes
Attach Attributes
Design Circuitry
'''
mFnAttr = OpenMaya.MFnNumericAttribute()
Ripple.mObj_Amplitude = mFnAttr.create("AmplitudeValue", "AmpVal", OpenMaya.MFnNumericData.kFloat, 0.0)
mFnAttr.setKeyable(1) # 可设置关键帧
mFnAttr.setMin(0.0)
mFnAttr.setMax(1.0)

Ripple.mObj_Displace = mFnAttr.create("DisplaceValue", "DispVal", OpenMaya.MFnNumericData.kFloat, 0.0)
mFnAttr.setKeyable(1)
mFnAttr.setMin(0.0)
mFnAttr.setMax(10.0)

Ripple.addAttribute(Ripple.mObj_Amplitude)
Ripple.addAttribute(Ripple.mObj_Displace)

#Ripple.outputGeom = mFnAttr.create()
'''
SWIG - Simplified Wrapper Interface Generator
'''
outputGeom = OpenMayaMPx.cvar.MPxGeometryFilter_outputGeom
Ripple.attributeAffects(Ripple.mObj_Amplitude, outputGeom)
Ripple.attributeAffects(Ripple.mObj_Displace, outputGeom)



def initializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject,"XZYW","1.0")# 发布者,版本号
try:
mplugin.registerNode(nodeName, nodeID, deformerCreator, nodeInitializer,
OpenMayaMPx.MPxNode.kDeformerNode)
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)



1
2
3
import maya.cmds as cmds
cmds.loadPlugin(r'C:\Users\XZYW\文档\maya\2023\zh_CN\scripts\rippleDeformer.py')
cmds.deformer(type = "RippleDeformer")

image-20220704225851994

3. Optimizing

  • 避免使用input Value来更新网格指针-lazy loading

  • 把DeformerNode_input存在dataBlock的output节点

设置顶点数据时,用顶点array一次性设置,而不是每个顶点设置一次

4. Painting Deformation(这一段开始大失败)

  • After user painting
  • Read the weight of each vertex获取每个顶点绘制的权重
  • weight: Use weight value in calculation

大概是由于版本的问题,在添加deformer以后,绘制里面没有办法找到绘制ripple deformer的权重

5. Accessory Objects for Deformer(失败)

  • Accessory Object/Node
    • Help deriving Deformation
    • Deletion of A object should delete Deformer node

Accessory worldMatrix->DeformerNode matrixAttr

image-20220705104054032

  • Accessory Node Setup()
    • Create object
    • connect Attributes
  • Accessory Attribute()