Hi all,

I've having a load of trouble with this. I've managed to get some complex 
(for me anyway) compound attributes set up and connected to objects in my 
scene, but right now I'm unable to get the "Blend Shape Multi Input" 
attribute to arrive as a plug to the compute() method in my scripted node. 

So I resorted to some trickery by looking for the "blendWeight" attribute 
instead when it changes, then getting om.MDataPlug.parent() which is the 
compound node, then re-getting the children of that compound node and their 
data. 

My attributes look like this

[image: node.PNG] <about:invalid#zClosurez>


All of this works except for one crucial thing, calling asMDataHandle()
childData = childPlug.asMDataHandle().data()

This seems to force the recompute of some things and sends my plugin into 
an infinite loop. Is there a better way to do this?

Code attached, it should work in maya 2018 (possibly earlier) in a scene 
with some blendshapes in it if you call connectBlendShapeNodes()

Thanks for any help!

-- 
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/43e35225-ada9-4f02-8055-e63231cd5a92%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
import sys
import os
import re 

from collections import defaultdict

import pymel.core as pm
import maya.api.OpenMaya as om

def maya_useNewAPI():
    pass


def pluginLoader(load):
    """
    Load or Unload the plugin defined in this module.

    Parameters:
    load : bool : True to load the plugin, False to unload it.
    """
    global __file__
    
    if __file__.endswith('.pyc'):
        __file__ = __file__ [:-1]
    
    _, plugin = os.path.split(__file__)
    pluginName = plugin.split('.')[0]
    
    if load:
        if not pm.pluginInfo(plugin, query=True, loaded=True):
            pm.loadPlugin(__file__, quiet=True)
    else:
        if pm.pluginInfo(plugin, query=True, loaded=True):
            pm.flushUndo()
            pm.unloadPlugin(plugin, force=True)
    
    return pluginName

def getBlendShapeAttrs():
    blendShapes = pm.ls( type = pm.nt.BlendShape )

    data = defaultdict(list)
    
    data[0] = blendShapes

    for bs in blendShapes:
        blendShapeInputs = bs.getGeometry()
        for bsi in blendShapeInputs:
            bsiNode = pm.PyNode(bsi)
            attrs = bsiNode.listAttr()
            for attr in attrs:
                foundColor = attr.find('_TC') > -1
                foundIndex = attr.find('_TI') > -1
                if foundColor or foundIndex: # regular string search fails on certain attributes
                    attrAlias = attr.attrName().split('_')[0]
                    data[attrAlias].append(attr)

    return data

def connectBlendShapeNodes():
    blendShapeAttrs = getBlendShapeAttrs()

    # load the plugin
    plugin = pluginLoader(True)
    pluginNode = pm.createNode(BlendVertexColors.nodeName)
    pluginAttrs = pluginNode.listAttr()

    blendShape = blendShapeAttrs.pop(0)[0] # TODO: support multiple blend shapes

    i = 0
    for attrAlias, attrs in blendShapeAttrs.items(): 
        for attr in attrs:
            if '_TC' in attr.attrName():
                # >> is Pymel syntax to connect an attribute
                attr >> pluginNode.blendShapeMultiInput[i].tensionColor
            if '_TI' in attr.attrName():
                attr >> pluginNode.blendShapeMultiInput[i].tensionIndex
            else:
                attr = pm.PyNode( blendShape + '.' + attrAlias )
                attr >> pluginNode.blendShapeMultiInput[i].blendWeight
        i += 1


class BlendVertexColors(om.MPxNode):

    nodeName = 'blendVertexColors'
    nodeId = om.MTypeId( 0xDAE1 )

    attrIn_blendShapeMultiInput = om.MObject()
    attrIn_tensionColor_01 = om.MObject()
    attrIn_tensionIndex_01 = om.MObject()
    attrIn_blendWeight = om.MObject()

    # Attribute hierarchy goes: colorPerVertex > vertexColor > vertexColorRGB >> vertexColorR,G,B
    attrOut_colorPerVertex = om.MObject()
    attrOut_vertexColor = om.MObject()
    attrOut_vertexColorRGB = om.MObject()
    attrOut_vertexAlpha = om.MObject()
    attrOut_colorPerFaceVertex = om.MObject()
    attrOut_vertexFaceColor = om.MObject()
    attrOut_vertexFaceColorRGB = om.MObject()
    attrOut_vertexFaceAlpha = om.MObject()
    vertColorOutput = om.MObject()

    def __init__(self):
        ''' constructor '''
        om.MPxNode.__init__(self)

    def compute(self, plug, dataBlock):
        print "Computing..."
        print plug.name()
        if( 'blendWeight' in plug.name() ):
            plugParent = plug.parent()
            numChildren = plugParent.numChildren()
            
            tensionColor = []
            tensionIndex = []
            blendWeight = 0

            for i in range(numChildren):
                childPlug = plugParent.child(i)
                attribute = childPlug.attribute()
                attributeFn = om.MFnAttribute( attribute )
                if attributeFn.name == 'tensionColor':
                    childData = childPlug.asMDataHandle().data()
                    tensionColor = om.MFnDoubleArrayData( childData ).array()
                    print tensionColor
                if attributeFn.name == 'tensionIndex':
                    childData = childPlug.asMDataHandle().data()
                    tensionIndex = om.MFnIntArrayData( childData ).array()
                    print tensionIndex
                if attributeFn.name == 'blendWeight':
                    childData = childPlug.asMDataHandle().data()
                    blendWeight = om.MFnNumericData( childData )
                    print blendWeight

            try:
                rgbValues = self.sortRGB( tensionIndex, tensionColor )
                print "Done", rgbValues
            except:
                print "Bad stuff"

            vertColorOutput_Handle = dataBlock.outputValue( BlendVertexColors.vertColorOutput )
            vertColorOutput_Handle.setMObject() #.setMObject() #?

    def sortRGB(self, vertIndices, vertColors):
        returnColors = {}
        for i, vertIndex in enumerate(vertIndices):
            for color in vertColors:
                if color > 1: # red
                    returnColors[ pm.nt.Color(color - 1, 0, 0) ]
                else: # blue
                    pass

    def combineVertColors(self, inputs=[]):
        output = 0
        for input in inputs:
            output += input
        return output

    @classmethod
    def nodeCreator(cls):
        ''' creates and instance of out node class and delivers to to maya as a pointer '''
        return cls()

    @classmethod
    def nodeInitializer(cls):
            ''' defines the input and output attributes as static varaibles in our plugin '''
            blendShapeMultiInput = om.MFnCompoundAttribute()
            doubleArrayAttrFn = om.MFnGenericAttribute()
            intArrayAttrFn = om.MFnGenericAttribute()
            intAttrFn = om.MFnNumericAttribute()

            ''' input attributes '''
            cls.attrIn_blendShapeMultiInput = blendShapeMultiInput.create( 'blendShapeMultiInput', 'mai' )
            cls.attrIn_tensionColor_01 = doubleArrayAttrFn.create( 'tensionColor', 'tc' )
            cls.attrIn_tensionIndex_01 = intArrayAttrFn.create( 'tensionIndex', 'ti' )
            cls.attrIn_blendWeight = intAttrFn.create( 'blendWeight', 'bw', om.MFnNumericData.kFloat )

            doubleArrayAttrFn.addDataType( om.MFnData.kDoubleArray )
            intArrayAttrFn.addDataType( om.MFnData.kIntArray )
            
            blendShapeMultiInput.array = True
            blendShapeMultiInput.addChild( cls.attrIn_tensionColor_01 )
            blendShapeMultiInput.addChild( cls.attrIn_tensionIndex_01 )
            blendShapeMultiInput.addChild( cls.attrIn_blendWeight )

            cls.addAttribute( cls.attrIn_blendShapeMultiInput )

            numAttrFn = om.MFnNumericAttribute()
            out_compAttrFn_parent = om.MFnCompoundAttribute()
            out_compAttrFn_child1 = om.MFnCompoundAttribute()
            out_compAttrFn_child2 = om.MFnCompoundAttribute()

            ''' output attribute '''
            cls.attrOut_colorPerVertex = out_compAttrFn_parent.create( 'colorPerVertex', 'cpvo' )
            cls.attrOut_vertexColor = out_compAttrFn_child1.create( 'vertexColor', 'vco' )
            cls.attrOut_vertexColorRGB = numAttrFn.createColor( 'vertexColorRGB', 'vcrgbo')
            cls.attrOut_vertexAlpha = numAttrFn.create( 'vertexAlpha', 'vao01', om.MFnNumericData.kFloat)
            
            cls.attrOut_vertexFaceColor = out_compAttrFn_child2.create( 'vertexFaceColor', 'vfco' )
            cls.attrOut_vertexFaceColorRGB = numAttrFn.createColor( 'vertexFaceColorRGB', 'vcfrgbo')
            cls.attrOut_vertexFaceAlpha = numAttrFn.create( 'vertexFaceAlpha', 'vfao', om.MFnNumericData.kFloat)

            out_compAttrFn_parent.addChild( cls.attrOut_vertexColor )

            out_compAttrFn_child1.array = True
            out_compAttrFn_child1.addChild( cls.attrOut_vertexColorRGB )
            out_compAttrFn_child1.addChild( cls.attrOut_vertexAlpha )
            out_compAttrFn_child1.addChild( cls.attrOut_vertexFaceColor )
            
            out_compAttrFn_child2.array = True
            out_compAttrFn_child2.addChild( cls.attrOut_vertexFaceColorRGB )
            out_compAttrFn_child2.addChild( cls.attrOut_vertexFaceAlpha )

            cls.addAttribute( cls.attrOut_colorPerVertex )
                
            cls.attributeAffects( cls.attrIn_blendWeight, cls.attrIn_blendShapeMultiInput )
            #cls.attributeAffects( cls.attrIn_blendShapeMultiInput, cls.attrOut_colorPerVertex )

            
def initializePlugin( mobject ):
    ''' initliize the plug-in'''
    mplugin = om.MFnPlugin( mobject )
    try:
        mplugin.registerNode( BlendVertexColors.nodeName, BlendVertexColors.nodeId, BlendVertexColors.nodeCreator, BlendVertexColors.nodeInitializer )
        print "Loaded plugin"
    except:
        sys.stderr.write( 'Failed to register node: ' + BlendVertexColors.nodeName )
        raise

def uninitializePlugin( mobject ):
    ''' uninitialize the plugin'''
    mplugin = om.MFnPlugin( mobject )
    try:
        mplugin.deregisterNode( BlendVertexColors.nodeId )
        print "Unloaded plugin"
    except:
        sys.stderr.write( 'Failed to deregister node: ' + BlendVertexColors.nodeName )
        raise

Reply via email to