所需模块:sys,OpenMaya,OpenMayaMPx,math,cmds
代码结构:定义节点名称及ID,变形算法类,定义变形器指针,为deformer Node定义添加属性。
nodeName = "RippleDeformer"
nodeID = om.MTypeId(0x102fff)
定义节点名称及ID
class Ripple(ommpx.MPxDeformerNode):
mObj_Amplitude = om.MObject()
mObj_Displace = om.MObject()
mObj_Matrix = om.MObject()
def __init__(self):
ommpx.MPxDeformerNode.__init__(self)
def deform(self, dataBlock,geoIterator,matrix,geometryIndex):
input = ommpx.cvar.MPxGeometryFilter_input
# 1.Attach a handle to input Array Attribute
dataHandleInputArray = dataBlock.outputArrayValue(input)
# 2.Jump to particular element
dataHandleInputArray.jumpToElement(geometryIndex)
# 3.Attach a handle to specific data block
dataHandleInputElement = dataHandleInputArray.outputValue()
# 4.Reach to the child - inputGeom
inputGeom = ommpx.cvar.MPxGeometryFilter_inputGeom
dataHandleInputGeom = dataHandleInputElement.child(inputGeom)
inMesh = dataHandleInputGeom.asMesh()
获取输入数组中的物体,因为我们要对物体进行操作
我们访问内置属性用:Attr = ommpx.cvar.MPxGeometryFilter_(attr)
获取当前数组的句柄:handleinputArray = dataBlock.outputArrayValue(Attr)
跳转到数组中的特定元素:handleinputArray.jumpToElement(geometryIndex)
获取当前数组元素的数据块的句柄:handleinputArray.outputValue()
特定数组元素构成:
访问特定元素的内置属性:ommpx.cvar.MPxGeometryFilter_inputGeom
inputGeom是特定元素的子属性,获取元素的子属性:dataHandleInputGeom = dataHandleInputElement.child(inputGeom)
将句柄的数据作为mesh返回:inMesh = dataHandleInputGeom.asMesh()
# Envelope
envelope = ommpx.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()
# matrix
dataHandleMatrix = dataBlock.inputValue(Ripple.mObj_Matrix)
matrixValue = dataHandleMatrix.asMatrix()
获取内置属性的值:
envelope = ommpx.cvar.MPxGeometryFilter_envelope dataHandleEnvelope = dataBlock.inputValue(envelope) envelopeValue = dataHandleEnvelope.asFloat()
获取自定义属性的值:
dataHandleAmplitude = dataBlock.inputValue(Ripple.mObj_Amplitude) amplitudeValue = dataHandleAmplitude.asFloat()
# read the translation from matrix
mTransMatrix = om.MTransformationMatrix(matrixValue)
translationValue = mTransMatrix.getTranslation(om.MSpace.kObject)
mFloatVectorArray_normal = om.MFloatVectorArray()
mFnMesh = om.MFnMesh(inMesh)
mFnMesh.getVertexNormals(False,mFloatVectorArray_normal,om.MSpace.kObject)
mPointArray_meshVert = om.MPointArray()
while( not geoIterator.isDone()):
pointPosition = geoIterator.position()# 返回当前点的位置
weight = self.weightValue(dataBlock,geometryIndex,geoIterator.index())
pointPosition.x = pointPosition.x + math.sin(geoIterator.index() + displaceValue + translationValue[0]) * amplitudeValue * mFloatVectorArray_normal[geoIterator.index()].x * weight * envelopeValue
pointPosition.y = pointPosition.y + math.sin(geoIterator.index() + displaceValue + translationValue[0]) * amplitudeValue * mFloatVectorArray_normal[geoIterator.index()].y * weight * envelopeValue
pointPosition.z = pointPosition.z + math.sin(geoIterator.index() + displaceValue + translationValue[0]) * amplitudeValue * mFloatVectorArray_normal[geoIterator.index()].z * weight * envelopeValue
mPointArray_meshVert.append(pointPosition)
#geoIterator.setPosition(pointPosition)
geoIterator.next()
geoIterator.setAllPositions(mPointArray_meshVert)
cmds.makePaintable("RippleDeformer", "weights", attrType="multiFloat", shapeMode="deformer")
获取matrix属性的变换矩阵:mTransMatrix = om.MTransformationMatrix(matrixValue)
将变换矩阵以厘米为单位返回转换的平移分量:translationValue = mTransMatrix.getTranslation(om.MSpace.kObject)
创建一个MFloatVector数组:mFloatVectorArray_normal = om.MFloatVectorArray()
返回物体的顶点常量,并将常量存储在数组内:
mFnMesh = om.MFnMesh(inMesh) mFnMesh.getVertexNormals(False,mFloatVectorArray_normal,om.MSpace.kObject)
判断是否已遍历所有项,若没有遍历完则让当前点执行变形算法并将新位置坐标添加到数组中;若遍历完成,一次性设置所有顶点的位置。
将新属性注册为“属性绘制”工具的可绘制属性:
cmds.makePaintable("RippleDeformer", "weights", attrType="multiFloat", shapeMode="deformer")
变形器通常需要一个辅助节点,如定位器,以控制变形的变化。这些辅助节点称为附件。附件节点是可选的,对变形器来说不是必需的。MPxGeometryFilter类的输入属性足以执行变形。只有当您想要使用附件来变形几何图形时,才应该实现accessoryNodeSetup()和accessoryAttribute()方法。
def accessoryNodeSetup(self, dagModifier):
# 1.create Accessory Object
mObjLocator = dagModifier.createNode("locator")
# 2.Establish Connection
mFnDependLocator = om.MFnDependencyNode(mObjLocator)
mPlugWorld = mFnDependLocator.findPlug("worldMatrix")
mobj_WorldAttr = mPlugWorld.attribute()
mstatusConnect = dagModifier.connect(mObjLocator,mobj_WorldAttr,self.thisMObject(),Ripple.mObj_Matrix)
return mstatusConnect
def accessoryAttribute(self):
return Ripple.mObj_Matrix
创建定位器,将定位器设置为附属节点,为该节点找到一个plug,返回该plug的属性,将locator属性与自定义Matrix属性连接。
def deformerCreator():
return ommpx.asMPxPtr(Ripple())
def nodeInitializer():
'''
create Attributes
Attach Attributes
Design Circuitry
'''
# 1.create Attributes
mFnAttr = om.MFnNumericAttribute()
Ripple.mObj_Amplitude = mFnAttr.create("AmplitudeValue","AmplitudeVal",om.MFnNumericData.kFloat,0.0)
mFnAttr.setKeyable(True)
mFnAttr.setMin(0.0)
mFnAttr.setMax(1.0)
Ripple.mObj_Displace = mFnAttr.create("DisplaceValue","DispVal",om.MFnNumericData.kFloat,0.0)
mFnAttr.setKeyable(True)
mFnAttr.setMin(0.0)
mFnAttr.setMax(10.0)
# 1.Create Matrix Attribute
mFnMatrixAttr = om.MFnMatrixAttribute()
Ripple.mObj_Matrix = mFnMatrixAttr.create("MatrixAttribute","matattr")
mFnMatrixAttr.setStorable(False)
mFnMatrixAttr.setConnectable(True)
# 2.Attach Attributes
Ripple.addAttribute(Ripple.mObj_Amplitude)
Ripple.addAttribute(Ripple.mObj_Displace)
Ripple.addAttribute(Ripple.mObj_Matrix)
'''
SWIG - Simplified Wrapper Interface Generator
'''
# 3.Design Circuitry
outputGeom = ommpx.cvar.MPxGeometryFilter_outputGeom
Ripple.attributeAffects(Ripple.mObj_Amplitude,outputGeom)
Ripple.attributeAffects(Ripple.mObj_Displace,outputGeom)
Ripple.attributeAffects(Ripple.mObj_Matrix,outputGeom)
初始化节点:创建节点属性,将属性添加到节点上,为自定义节点属性设计Circuitry。
参考文档:Help