degne...@googlemail.com
unread,Nov 19, 2017, 5:12:19 PM11/19/17Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to Python Programming for Autodesk Maya
hi together,
I have been trying to write a custom deformer using the maya python api which basically is a shrink wrap deformer using a custom vector to project each vertex to the another mesh.
The deformer works fine as is. I really would like to add one option though which I cannot figure out how to achieve as I am new to the api and the logics of it in general. I would like to add an array attribute to the deformer node which for each input geometry vertex saves the index of another vertex which should be included into the calculation of the deform function.
My question is: How do I create the array attribute and also how do I populate and access it in the deform function?
I guess I have already somewhat figured out how to create the Array using setArray() function and also adding child attributes to it but I still have troubles understanding where and how to populate and access the array attribute. There is a lot of information out there concerning MPlugs and arrayDataBuilder but I simply have not been able to understand it. Can somebody provide me with an example or explain me how to properly do using the python api? Any help is greatly appreciated!
This is the code, that I was able put together with the examples available online:
import maya.OpenMaya as OpenMaya
import maya.OpenMayaAnim as OpenMayaAnim
import maya.OpenMayaMPx as OpenMayaMPx
import maya.cmds as cmds
class surfaceSlideDeformer(OpenMayaMPx.MPxDeformerNode):
kPluginNodeId = OpenMaya.MTypeId(0x00000012)
kPluginNodeTypeName = "surfaceSlideDeformer"
bindData = OpenMaya.MObject()
sampleWeights = OpenMaya.MObject()
def __init__(self):
OpenMayaMPx.MPxDeformerNode.__init__(self)
self.accelParameters = OpenMaya.MMeshIsectAccelParams() # speeds up intersect calculation
def deform(self, block, geoItr, matrix, index):
# get ENVELOPE
envelope = OpenMayaMPx.cvar.MPxGeometryFilter_envelope
envelopeHandle = block.inputValue(envelope)
envelopeVal = envelopeHandle.asFloat()
if envelopeVal!=0:
# get target MESH (as worldMesh)
targetHandle = block.inputValue(self.targetMesh)
inTargetMesh = targetHandle.asMesh()
if not inTargetMesh.isNull():
#get target fn mesh
inTargetFn = OpenMaya.MFnMesh(inTargetMesh)
inMesh = self.get_input_geom(block, index)
inMeshFn = OpenMaya.MFnMesh(inMesh)
inPointArray = OpenMaya.MPointArray()
inMeshFn.getPoints(inPointArray, OpenMaya.MSpace.kWorld)
# create array to store final points and set to correct length
length = inPointArray.length()
finalPositionArray = OpenMaya.MPointArray()
finalPositionArray.setLength(length)
finalPositionArray = inPointArray
# loop through all points
while not geoItr.isDone():
w = self.weightValue(block, index, geoItr.index())
point = inPointArray[geoItr.index()]
raySource = OpenMaya.MFloatPoint(point.x, point.y, point.z)
rayDirection = OpenMaya.MVector()
inMeshFn.getVertexNormal(geoItr.index(), False, rayDirection)
rayDirection = OpenMaya.MFloatVector(rayDirection.x, 0.0, rayDirection.z)
hitPoint = OpenMaya.MFloatPoint()
# rest of the args
hitFacePtr = OpenMaya.MScriptUtil().asIntPtr()
idsSorted = False
testBothDirections = True
faceIds = None
triIds = None
accelParams = self.accelParameters
hitRayParam = None
hitTriangle = None
hitBary1 = None
hitBary2 = None
maxParamPtr = 99999999
hit = inTargetFn.closestIntersection(raySource,
rayDirection,
faceIds,
triIds,
idsSorted,
OpenMaya.MSpace.kWorld,
maxParamPtr,
testBothDirections,
accelParams,
hitPoint,
hitRayParam,
hitFacePtr,
hitTriangle,
hitBary1,
hitBary2)
if hit:
finalPositionArray.set(OpenMaya.MPoint(point.x + envelopeVal*w*(hitPoint.x-point.x), point.y + envelopeVal*w*(hitPoint.y-point.y), point.z + envelopeVal*w*(hitPoint.z-point.z)), geoItr.index())
else:
finalPositionArray.set(point, geoItr.index())
geoItr.next()
inMeshFn.setPoints(finalPositionArray, OpenMaya.MSpace.kWorld)
def get_input_geom(self, block, index):
input_attr = OpenMayaMPx.cvar.MPxGeometryFilter_input
input_geom_attr = OpenMayaMPx.cvar.MPxGeometryFilter_inputGeom
input_handle = block.outputArrayValue(input_attr)
input_handle.jumpToElement(index)
input_geom_obj = input_handle.outputValue().child(input_geom_attr).asMesh()
return input_geom_obj
def creator():
return OpenMayaMPx.asMPxPtr(surfaceSlideDeformer())
def initialize():
gAttr = OpenMaya.MFnGenericAttribute()
mAttr = OpenMaya.MFnMatrixAttribute()
nAttr = OpenMaya.MFnNumericAttribute()
tAttr = OpenMaya.MFnTypedAttribute()
cAttr = OpenMaya.MFnCompoundAttribute()
outMesh = OpenMayaMPx.cvar.MPxGeometryFilter_outputGeom
surfaceSlideDeformer.targetMesh = gAttr.create("targetMesh", "target")
gAttr.addDataAccept(OpenMaya.MFnData.kMesh)
surfaceSlideDeformer.addAttribute(surfaceSlideDeformer.targetMesh)
surfaceSlideDeformer.sampleWeights = nAttr.create('sampleWeights','sampleWeights',OpenMaya.MFnNumericData.k2Int)
nAttr.setArray(True)
surfaceSlideDeformer.bindData = cAttr.create('bindData','bindData')
cAttr.setArray(True)
cAttr.setStorable(True)
cAttr.addChild(surfaceSlideDeformer.sampleWeights)
surfaceSlideDeformer.addAttribute(surfaceSlideDeformer.bindData)
surfaceSlideDeformer.attributeAffects(surfaceSlideDeformer.bindData, outMesh)
surfaceSlideDeformer.attributeAffects(surfaceSlideDeformer.targetMesh, outMesh)
cmds.makePaintable('surfaceSlideDeformer', 'weights', attrType='multiFloat', shapeMode='deformer')
def initializePlugin(obj):
plugin = OpenMayaMPx.MFnPlugin(obj, 'Degner', '1.0', 'Any')
try:
plugin.registerNode('surfaceSlideDeformer', surfaceSlideDeformer.kPluginNodeId, creator, initialize,
OpenMayaMPx.MPxNode.kDeformerNode)
except:
raise RuntimeError, 'Failed to register node'
def uninitializePlugin(obj):
plugin = OpenMayaMPx.MFnPlugin(obj)
try:
plugin.deregisterNode(surfaceSlideDeformer.kPluginNodeId)
except:
raise RuntimeError, 'Failed to deregister node'