Custom paintable attribute NEED HELP!!!

119 views
Skip to first unread message

徐一雄

unread,
Jan 9, 2019, 5:50:57 AM1/9/19
to Python Programming for Autodesk Maya
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

Tenghao Wang

unread,
Jan 9, 2019, 1:09:02 PM1/9/19
to python_in...@googlegroups.com
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( jiggleMapHandle.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


--
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_m...@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.
Message has been deleted
Message has been deleted
Message has been deleted

徐一雄

unread,
Jan 10, 2019, 9:00:48 PM1/10/19
to Python Programming for Autodesk Maya
Hi Tenghao,
Thank you for your suggestion.
It works.
Thank you!~

在 2019年1月10日星期四 UTC+8上午2:09:02,Tenghao Wang写道:
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

Tenghao Wang

unread,
Jan 10, 2019, 10:51:40 PM1/10/19
to python_in...@googlegroups.com
Glad it works!

To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

--
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_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/8e76b1ee-5363-4aba-9014-5594b521477f%40googlegroups.com.

徐一雄

unread,
Jan 12, 2019, 3:10:24 AM1/12/19
to Python Programming for Autodesk Maya
Hi Tenghao,

One more question, if I use my jiggle deformer on 2 different type of polygon mesh, for example, a polygonSphere and polygonCube
In Interactive playback,  I found that when I move the one, the other mesh will also jiggling, or the components of the other polygon will jiggling.
It is really weird...
Is it right?

Yixiong Xu
2019.01.12

在 2019年1月11日星期五 UTC+8上午11:51:40,Tenghao Wang写道:
Glad it works!

To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

--
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+unsub...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages