Re: MPxLocatorNode and compute troubleshooting (with example code)

1,190 views
Skip to first unread message

cedric bazillou

unread,
Jun 7, 2012, 3:32:25 PM6/7/12
to python_in...@googlegroups.com
Hello,
(lets call you Nero... )

I think you can explain why your compute is not triggered: the dependency graph in maya is not informed that your output attribute needs to be update: you have nothing connected to it , right?
Nothing original but how about writing a node to compute your pointList and plug it to your locator that will only draw from a kPointArray/kVectorArray input attribute? I have play with this idea and it works: http://forums.cgsociety.org/showpost.php?p=7280472&postcount=14.


Le mardi 5 juin 2012 18:35:15 UTC+2, WhileRomeBurns a écrit :
So basically I've got a python node called simpleLocator with an attribute called pointCount (type kInt) which is used to generate some random points. These points can be passed out as an array with the attribute outPoints (type kDoubleArray for this example). I've setup attributeAffects() so that outPoints depends on pointCount, so it should update if the user edits the number of points. This node needs to draw the points every frame with OpenGL as well, but only compute as needed. So far so good. Here's my example code (also attached to this post), stripped to the bare essentials and it almost works:



When compute() is called though, plug never equals aOutPoints. Ever, ever.

    def compute( self, plug, data ):
        if plug == simpleLocator.aOutPoints:
            print( 'aOutPoints needs to be computed, but we never get here...' )
            return om.MStatus.kSuccess
        else:
            return om.MStatus.kUnknownParameter


What's normal practice here? Should I just query my simpleLocator.aPointCount every time draw is called and only call generatePoints() if the value of aPointCount has been changed? Should I derive from a node other than MPxLocator and implement my own draw method? Does MPxLocator behave different in C++? Any help, any insight would be greatly appreciated. Thanks.

-shawn
PS- If you're curious, the real node is generating blue noise for thousands of points and is fairly expensive to calculate.

Judah Baron

unread,
Jun 7, 2012, 5:11:44 PM6/7/12
to python_in...@googlegroups.com
You don't need connect another node to pull the data from the plug and trigger compute. It sounds like you are on the right track with the query in draw. You can either use a real attribute, or create a dummy that is used solely for the purpose of triggering compute. You then need to make sure your attribute dependency is set up properly with attributeAffects, or setDependentsDirty. Once you've done this, pulling the plug's value from within draw will dirty the plug, triggering compute. You'll need to do this early in draw, obviously - befor you draw anything, for the change to take effect.

cedric bazillou

unread,
Jun 7, 2012, 7:31:15 PM6/7/12
to python_in...@googlegroups.com
You are right Judah, the other node is not mandatory: it was just a personal preference: separating data processing( noise point ) from drawing ( the locator ).If you duplicate your locator you dont need to compute several time your point list( when you need the same point list of course ). In my case it was easier to stick to the regular  maya workflow( data flows from one node to another )
I would also use a MVectorArray initialized with your self.pointCount value  but its just my way of doing things.

Judah Baron

unread,
Jun 7, 2012, 9:06:30 PM6/7/12
to python_in...@googlegroups.com
Right. It depends on the indended use for this node: if there will be some sharing of data, then passing the data, or a reference to the data, throught the dg makes sense. 

WhileRomeBurns

unread,
Jun 8, 2012, 1:51:19 PM6/8/12
to python_in...@googlegroups.com
Thanks for the quick replies! So he basically tricks Maya into dirtying his plug in the draw method? Nice. So in my example, I would query the value of a third dummy attribute- something lighter weight than an array like a float or int and use that to force the eval? Can do!


 >  how about writing a node to compute your pointList and plug it to your locator that will only draw from  
Absolutely the way to go, but I thought I would save time and test the idea in one node. But then nothing worked :)


Additionally, I'm now fighting python just to call compute with MFnTypedAttributes. Two examples, slightly modified versions of Farsheed's skeleton code. The first one has MFnNumericAttribute as the output attribute and it calls the compute method as expected. The second one is bunk though and I cannot figure out why. Hmm. Take a look:

nodeNumeric.py:
Works a charm, compute gets called.

nodeTyped.py
Compute never gets called. Silently fails? Only changed the attr type to TypedAttr and kDoubleArray. Nada. Zilch. Zippo!

Did I miss something obvious? Thanks.
-shawn


cedric bazillou

unread,
Jun 8, 2012, 4:29:55 PM6/8/12
to python_in...@googlegroups.com
first In your plugin declaration with the kDoubleArray output I would rather correct those lines( things can be done in a lot of different ways, this is how i do it ):
"
def initializePlugin(mobject):
    fnPlugin = omMPx.MFnPlugin(mobject)
    fnPlugin.registerNode(nodeType, nodeId, nodeCreator, nodeInitializer)
"
by
"
kPluginNodeName = "spaceSwitch" #<-- replace by your plugin name
kPluginNodeId = OpenMaya.MTypeId(your_Custom_ID_number here)
def initializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject, "AuthorName", "VersionNum", "Any")
mplugin.registerNode( kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer, OpenMayaMPx.MPxNode.kDependNode)# <-- As you can see I use the type of the node here a dependency node
"

then In your compute method there is no code to write some value on your output and also no setClean call.
Your node must also be connected to another node. just few question bellow,
Are your example the complete code for your nodes?
Do you have an ascii maya file that can be used as an example?
Do you have any prior experience with the API?
Have you a basic understanding of the concept of hierarchy , connections , attributes and plug ?( DAG versus dependency nodes )

WhileRomeBurns

unread,
Jun 9, 2012, 4:26:41 PM6/9/12
to python_in...@googlegroups.com
In the real plugin, I do declare "Author Name", "Plug Version", etc. The point of my example was to remove all that code (which Maya allows- it gets initialized to default values) to make it clear to myself, and others, what the problem is. Hence I cut out the normal try/except error stuff as well- cleaner examples are nice.


>  then In your compute method there is no code to write some value on your output and also no setClean call. 
Doesn't matter matter if I set it clean- compute never gets called in my example, so adding in setClean() or any other function call isn't relevant as far as I can tell- it never gets dirtied.


>  Your node must also be connected to another node.
Does it always? There are nodes that update on attribute change without being connected. My first example does this. Change 'input' int attribute and compute() gets called, and 'output' updates. The dirty/clean stuff works a charm- I told Maya that attributeAffects(MyNode.aInput, MyNode.aOutput) and boom- input did indeed affect output as advertised! So saying it must be connected is untrue for this case of kInt or KFloat, both of which I've tested.

Now if I do attributeAffects(MyNode.aInput, MyNode.aOutput) with aOutput being an MFnTypedAttribute, compute() never gets called. attributeAffects() does not work as described in the API docs (for this simple one node case) and I want to know why. I assume there is a logical, maybe even obvious, explanation; maybe it's an optimization on Maya's part because I haven't actually created an array of data for the aOutput attr yet? 


Do you have any prior experience with the API? 
Mostly writing translators, compiling others' c++ nodes to work with my version of maya/environment. Just got into python api stuff though.


Have you a basic understanding of the concept of hierarchy , connections , attributes and plug ?( DAG versus dependency nodes )
I would say that I definitely have at least basic understanding, but I came here for the people with the advanced understanding. :)


Thanks again for your patience. I really want to resolve this simple example before I start porting my code to Maya nodes.
-shawn

Judah Baron

unread,
Jun 9, 2012, 5:37:46 PM6/9/12
to python_in...@googlegroups.com
You may benefit from at least testing out the setDependentsDirty call. Typed attributes are a bit more complex than standard base type attributes and Maya may handle them differently - I have no direct experience using them in compute. Unlike compute, setDependentsDirty is called every time an attribute value changes, allowing you to dirty the plugs required for your node to compute when needed. It's also good for dynamic multis and compounds, allowing you to pinpoint your computation in a manner not possible by using attributeAffects.

-J

cedric bazillou

unread,
Jun 9, 2012, 8:03:58 PM6/9/12
to python_in...@googlegroups.com
If you have nothing connected the compute method is triggered by either a UI ( think attribute editor or any other connectControl/attributeControl  element), when it is selected or visible: I rarely use setDependsDirty: my node use basic relationship and attributeAffects is enough for me.

I have used pretty much all type of attribute as input and output in python and C++( not the generic one that accept different type of data yet ).
What works for me is is to let maya control the dirty bit propagation between connected attributes.

lets examine your node:
MyNode.aOutput = tAttr.create('output', 'output', om.MFnData.kDoubleArray)
this is a typeAttribute:
you can write and read from it several MFNData like MFnMatrixData, MFnMeshData,MFnArrayAttrsData,  MFnComponentListData,  MFnDoubleArrayData( etc more info on the documentation can be found).

Depending on your data type you must use the appropriate MFnfunction:
here MFnDoubleArrayData ()

outHandle = dataBlock.outputValue(MyNode.aOutput)

to write your data, you set an MObject created from this MFNDoubleArrayData:

#MObject      create (const MDoubleArray &in, MStatus *ReturnStatus=NULL) #<--- C++ notation

Lets say you have create a MDoubleArray: and fill it
OuputList = OpenMaya.MDoubleArray()

#here expand and fill your value
outputDataFn = OpenMaya.MFNDoubleArrayData()
outputDataObj = outputDataFn.create(OuputList)

outHandle.setMObject(outputDataObj)
outHandle.setClean()

Let me know if it still refuse to works,
Reply all
Reply to author
Forward
0 new messages