Thank you for your reply.
I change some code and now I can read the attributes from paintable 
attributes.
But when I paint the attributes, it doesn't work on my mesh.
I don't know what's wrong with my code.
Can you help me?
Thank you very much.

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.jiggleMapArray = 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())

            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

        # perGeometry
        hGeo = dataBlock.inputArrayValue(JiggleDeformerNode.perGeo)

        self.jump2Element(hGeo, geoIndex)

        hPerGeo = hGeo.inputValue()

        hJiggleMap = 
om.MArrayDataHandle(hPerGeo.child(JiggleDeformerNode.jiggleMap))

        geoIterator.reset()

        self.jiggleMapArray.setLength(geoIterator.count())

        for i in range(geoIterator.count()):

            self.jump2Element(hJiggleMap, geoIterator.index())

            # self.jiggleMapArray.append(hJiggleMap.inputValue().asFloat())

            self.jiggleMapArray.set(hJiggleMap.inputValue().asFloat(), 
geoIterator.index())

            geoIterator.next()

        # print self.jiggleMapArray.length()
        # print geoIterator.count()

        # 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
            weight = self.weightValue(dataBlock, geoIndex, geoIterator.index())

            # jiggleMap
            jiggleMapVal = self.jiggleMapArray[geoIterator.index()]

            # make point[i] back to local space
            points.set(points[geoIterator.index()] + ((newPos * 
local2WorldMatrix.inverse()) - points[geoIterator.index()]) * weight * 
envelopeValue * jiggleMapVal,
                       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.jumpToElement(index):
        if index not in range(arrayHandle.elementCount()):

            builder = arrayHandle.builder()

            builder.addElement(index)

            arrayHandle.set(builder)

            arrayHandle.jumpToElement(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.05)
    MFnNumericAttr.setKeyable(1)
    MFnNumericAttr.setMin(0.0)
    MFnNumericAttr.setMax(1.0)

    # stiffness
    JiggleDeformerNode.stiffVal = MFnNumericAttr.create('stiffness', 'stiff', 
om.MFnNumericData.kFloat, 0.05)
    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

Yixiong Xu
2019.01.10

在 2019年1月10日星期四 UTC+8上午2:09:02,Tenghao Wang写道:
>
> Hey Yixiong,
> ,
>
> You need to create a float list to store the value per vertex: jiggleMap = 
> [] and then read the data from datahandle:
> sudo code:
> MArrayDataHandle jiggleMapHandle = mPerGeometryHandle.child(mJiggleMap) 
> jumpToElement(jiggleMapHandle, geoIterator.index()) jiggleMap.append( j
> iggleMapHandle.inputValue().asFloat()) and then you can apply the value 
> under this loop: 
>
> while not geoIterator.isDone():
>
> value_per_vertex = jiggleMap[geoIterator.index()]
> Hope this helps! Tenghao Wang Sr. Technical Artist Visual Concepts 
>
>
> On Wed, Jan 9, 2019 at 2:51 AM 徐一雄 <xuyixi...@gmail.com <javascript:>> 
> wrote:
>
>> 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 <javascript:>.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/python_inside_maya/21fb16d9-abe6-4949-a9a0-9a66ecb8dbd4%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/python_inside_maya/21fb16d9-abe6-4949-a9a0-9a66ecb8dbd4%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>> For more options, visit https://groups.google.com/d/optout.
>>
>

-- 
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/3db2691a-a3a4-4526-8439-7855586590bb%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to