Hello, everyone: I'm now stuck into a problem of how to make a custom attribute work in a custom deformer node(MPxDeformerNode) in python. As I known, I need to add 2 multi attributes: one for record per-vertex values and the other (parent) multi attributeis to store values for multiple shapes. For now, i have successfully add 2 multi attributes and set one as the other's parent. But I don't know how to get the value per-vertex in the deform function. Can anyone help me to make the following code work? Thank you very much. Two multi attributes: *jiggleMap *for store value per-vertex and *perGeo *is the parent multi attribute.
import maya.OpenMaya as om import maya.OpenMayaMPx as ompx import maya.cmds as cmds nodeName = 'CustomJiggleDeformer' nodeID = om.MTypeId(0xBEEF6) class JiggleDeformerNode(ompx.MPxDeformerNode): # input dampingVal = om.MObject() stiffVal = om.MObject() goalPos = om.MObject() jiggleMap = om.MObject() perGeo = om.MObject() worldMatrix = om.MObject() # make ture to connect 'time1.outTime' to 'CustomJiggleDeformer#.time' for stable simulation. time = om.MObject() def __init__(self): ompx.MPxDeformerNode.__init__(self) self.currentPositions = om.MPointArray() self.previousPositions = om.MPointArray() self.initializeFlag = False self.previousTime = om.MTime() self.perGeo = om.MFloatArray() def deform(self, dataBlock, geoIterator, local2WorldMatrix, geoIndex): input = ompx.cvar.MPxGeometryFilter_input dataHandleInputArray = dataBlock.outputArrayValue(input) dataHandleInputArray.jumpToElement(geoIndex) dataHandleInputElement = dataHandleInputArray.outputValue() # inputMesh inputGeom = ompx.cvar.MPxGeometryFilter_inputGeom dataHandleInputGeom = dataHandleInputElement.child(inputGeom) inputMesh = dataHandleInputGeom.asMesh() # MFnMesh inputMFnMesh = om.MFnMesh(inputMesh) # Envelope envelope = ompx.cvar.MPxGeometryFilter_envelope dataHandleEnvolope = dataBlock.inputValue(envelope) envelopeValue = dataHandleEnvolope.asFloat() # damping dataHandleDamping = dataBlock.inputValue(JiggleDeformerNode.dampingVal) damping = dataHandleDamping.asFloat() # stiffness dataHandleStiff = dataBlock.inputValue(JiggleDeformerNode.stiffVal) stiff = dataHandleStiff.asFloat() # time dataHandleTime = dataBlock.inputValue(JiggleDeformerNode.time) currentTime = dataHandleTime.asTime() # points' positions in local space points = om.MPointArray() geoIterator.allPositions(points) # test initialize flag for the first time if not self.initializeFlag: self.currentPositions.setLength(geoIterator.count()) self.previousPositions.setLength(geoIterator.count()) # perGeometry hGeo = om.MArrayDataHandle(dataBlock.inputArrayValue(JiggleDeformerNode.perGeo)) # self.jump2Element(hGeo, geoIndex) hGeoCount = hGeo.elementCount() print 'hGeoCount: ' + str(hGeoCount) if hGeoCount == 0: return for i in range(hGeoCount): hGeo.jumpToElement(i) # self.jump2Element(hGeo, geoIndex) hPerGeo = om.MArrayDataHandle(hGeo.inputArrayValue()) hPerGeoCount = hPerGeo.elementCount() print 'hPerGeoCount: ' + str(hPerGeoCount) for i in range(hPerGeoCount): hPerGeo.jumpToElement(i) self.perGeo.append(hPerGeo.inputValue().asFloat()) for i in range(points.length()): self.currentPositions.set(points[i] * local2WorldMatrix, i) self.previousPositions.set(self.currentPositions[i], i) self.previousTime = currentTime self.initializeFlag = True # for stable simulation, check the time difference whether it is 1 frame or not timeDiff = currentTime.value() - self.previousTime.value() if timeDiff > 1.0 or timeDiff < 0.0: self.initializeFlag = False self.previousTime = currentTime # dataBlock.setClean() return # following lines are just like a FOR loop # for i in range(geoIterator.count()): # ...... while not geoIterator.isDone(): goal = points[geoIterator.index()] * local2WorldMatrix # basic algorithm for jiggle effect velocity = (self.currentPositions[geoIterator.index()] - self.previousPositions[geoIterator.index()]) * (1.0 - damping) newPos = self.currentPositions[geoIterator.index()] + velocity goalVector = (goal - newPos) * stiff newPos += goalVector # store value for the next computing self.previousPositions.set(self.currentPositions[geoIterator.index()], geoIterator.index()) self.currentPositions.set(newPos, geoIterator.index()) self.previousTime = om.MTime(currentTime) # weight and envelope weight = self.weightValue(dataBlock, geoIndex, geoIterator.index()) # make point[i] back to local space points.set(points[geoIterator.index()] + ((newPos * local2WorldMatrix.inverse()) - points[geoIterator.index()]) * weight * envelopeValue * jiggleMapArray[geoIterator.index()], geoIterator.index()) # make it to go to the next iter(loop) geoIterator.next() # set the position after iter all points of the geometry geoIterator.setAllPositions(points) def jump2Element(self, arrayHandle, index): # if not arrayHandle.jumpToArrayElement(index): builder = arrayHandle.builder() builder.addElement(index) arrayHandle.set(builder) arrayHandle.jumpToArrayElement(index) def deformerCreator(): return ompx.asMPxPtr(JiggleDeformerNode()) def nodeInitializer(): MFnNumericAttr = om.MFnNumericAttribute() MFnUnitAttr = om.MFnUnitAttribute() MFnMatrixAttr = om.MFnMatrixAttribute() MFnCompoundAttr = om.MFnCompoundAttribute() # Create Attributes # damping JiggleDeformerNode.dampingVal = MFnNumericAttr.create('damping', 'damp', om.MFnNumericData.kFloat, 0.1) MFnNumericAttr.setKeyable(1) MFnNumericAttr.setMin(0.0) MFnNumericAttr.setMax(1.0) # stiffness JiggleDeformerNode.stiffVal = MFnNumericAttr.create('stiffness', 'stiff', om.MFnNumericData.kFloat, 0.1) MFnNumericAttr.setKeyable(1) MFnNumericAttr.setMin(0.0) MFnNumericAttr.setMax(1.0) # time JiggleDeformerNode.time = MFnUnitAttr.create('time', 'time', om.MFnUnitAttribute.kTime, 0.0) MFnUnitAttr.setWritable(1) MFnUnitAttr.setKeyable(1) # world Matrix for trigger the deform when user is dragging the geometry # it is useless for the basic algorithm JiggleDeformerNode.worldMatrix = MFnMatrixAttr.create('worldMatrix', 'worldMat') # jiggle map JiggleDeformerNode.jiggleMap = MFnNumericAttr.create('jiggleMap', 'jiggle', om.MFnNumericData.kFloat, 0.0) MFnNumericAttr.setMin(0.0) MFnNumericAttr.setMax(1.0) MFnNumericAttr.setArray(True) MFnNumericAttr.setUsesArrayDataBuilder(True) # perGeometry JiggleDeformerNode.perGeo = MFnCompoundAttr.create('perGeometry', 'perGeo') MFnCompoundAttr.setArray(True) # MFnCompoundAttr.addChild(JiggleDeformerNode.worldMatrix) MFnCompoundAttr.addChild(JiggleDeformerNode.jiggleMap) MFnCompoundAttr.setUsesArrayDataBuilder(True) # outputGeom outputGeom = ompx.cvar.MPxGeometryFilter_outputGeom # Attach Attributes JiggleDeformerNode.addAttribute(JiggleDeformerNode.dampingVal) JiggleDeformerNode.addAttribute(JiggleDeformerNode.stiffVal) JiggleDeformerNode.addAttribute(JiggleDeformerNode.time) JiggleDeformerNode.addAttribute(JiggleDeformerNode.worldMatrix) JiggleDeformerNode.addAttribute(JiggleDeformerNode.perGeo) # Design Circuitry JiggleDeformerNode.attributeAffects(JiggleDeformerNode.dampingVal, outputGeom) JiggleDeformerNode.attributeAffects(JiggleDeformerNode.stiffVal, outputGeom) JiggleDeformerNode.attributeAffects(JiggleDeformerNode.time, outputGeom) JiggleDeformerNode.attributeAffects(JiggleDeformerNode.worldMatrix, outputGeom) JiggleDeformerNode.attributeAffects(JiggleDeformerNode.jiggleMap, outputGeom) def initializePlugin(MObj): MPlugin = ompx.MFnPlugin(MObj, 'Yixiong Xu', '1.0') try: MPlugin.registerNode(nodeName, nodeID, deformerCreator, nodeInitializer, ompx.MPxNode.kDeformerNode) # paint default weights cmds.makePaintable(nodeName, 'weights', at='multiFloat', sm='deformer') cmds.makePaintable(nodeName, 'jiggleMap', at='multiFloat', sm='deformer') except: raise RuntimeError print 'Failed to register command: %s .\n' % nodeName def uninitializePlugin(MObj): MPlugin = ompx.MFnPlugin(MObj) try: MPlugin.deregisterNode(nodeID) except: raise RuntimeError print 'Failed to de-register command: %s .\n' % nodeName -- You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group. To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/21fb16d9-abe6-4949-a9a0-9a66ecb8dbd4%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.