Compute always called for an array attr which uses an MArrayDataBuilder?

41 views
Skip to first unread message

Paul Molodowitch

unread,
Aug 14, 2017, 7:25:48 PM8/14/17
to python_inside_maya

Hi all - I’m trying to make a custom MPxNode that has an array attribute, that I’m building with an MArrayDataBuilder.

However, even thought I call both MArrayDataHandle.setClean() and setAllClean() after building the array, the compute seems to always get called whenever I call getAttr on the array attribute without an index, and whenever I call evaluateNumElements(). I can, however, call getAttr on a specific element - getAttr myNode.myAttr[3] - without triggering the compute.

Is this normal?

Here’s some code to illustrate what I mean - you can execute this straight from a script editor:

from pymel.api.plugins import DependNode
import maya.OpenMaya as om

class MyNode(DependNode):
    _typeId = om.MTypeId(0x812EF)
    _name = 'MyNode'

    @classmethod
    def initialize(cls):
        # input
        nAttr = om.MFnNumericAttribute()
        cls.input = nAttr.create( "input", "in", om.MFnNumericData.kFloat, 0.0 )
        nAttr.setStorable(True)
        cls.addAttribute(cls.input)

        nAttr = om.MFnNumericAttribute()
        cls.myAttr = nAttr.create("myAttr", "mya", om.MFnNumericData.kFloat, 0.0)
        nAttr.setStorable(True)
        nAttr.setArray(True)
        nAttr.setUsesArrayDataBuilder(True)
        cls.addAttribute(cls.myAttr)
        cls.attributeAffects(cls.input, cls.myAttr)

    def compute(self, plug, dataBlock):
        print "compute called on %s" % plug.name()
        if plug == self.myAttr:
            arrayHandle = dataBlock.outputArrayValue(self.myAttr)
            numElements = arrayHandle.elementCount()
            print "numElements: ", numElements
            if arrayHandle.elementCount() < 10:
                builder = arrayHandle.builder()
                elemHandle = builder.addLast()
                elemHandle.setFloat(numElements)
                elemHandle.setClean()
                arrayHandle.set(builder)
                arrayHandle.setClean()
                arrayHandle.setAllClean()
                print "new numElements: ", arrayHandle.elementCount()
            return
        elif plug == self.input:
            dataBlock.setClean(self.input)
            return
        return om.kUnknownParameter
MyNode.register()

import pymel.core as pm
import maya.cmds as cmds
mynode = pm.createNode('MyNode')
attrName = "%s.myAttr" %mynode
print cmds.getAttr(attrName)
print mynode.myAttr.evaluateNumElements()
print mynode.myAttr.numElements()
print "dirty?", mynode.myAttr.isDirty()
print cmds.getAttr(attrName)

A few notes:

  • This reproduction code is in Python, but I came across this while writing C++. The results seem the same.
  • The “attributeAffects” bit seems to be necessary - without it, the compute is apparently never called.

Paul Molodowitch

unread,
Aug 14, 2017, 9:00:49 PM8/14/17
to python_inside_maya
So, found a solution - it seems like MArrayDataHandle.setClean() / setAllClean() are buggy - or else I'm using them wrong somehow.  If we switch the above "setClean" statements to instead use dataBlock.setClean, everything works as expected, with compute run only once (unless the input is changed).

Paul Molodowitch

unread,
Aug 14, 2017, 9:27:43 PM8/14/17
to python_inside_maya
Oops... I guess I should have said, just switch the setClean... there is no MDataBlock.setAllClean.
Reply all
Reply to author
Forward
0 new messages