View Full Version : python node questions (api)
12 December 2011, 10:28 PM
I have three API questions I was hoping someone here might be able to shed some light on.
1) I'd like to have a connectable MFnNumericAttribute that's an array. It would be nice for it to have a variable size, but I can also set it to be a large locked size. My question is: what's the best way to initialize one of these? If I set it up in the initializer and add it to the node, it starts empty. So far what I've been doing is making a "firstRun" variable inside the class that starts as True-- when it's True, I go in and use an array builder to populate it with default values. Is this bad? Will I overwrite data later, for example on file load?
2) How can I do attributeAffects properly with array and point attributes? I tried creating a point attribute and reacting to it in my MPxNode's compute, but instead of getting the plug for the attribute itself I was getting the plugs for the attribute's three children.
3) Is there an easy, accurate way to get the parametric length of a nurbs surface along one of its parameters (essentially like duplicating a surface curve along a length of the surface and using arclen -ch) in the API without having to create a duplicated surface curve and extra DAG transform? Right now I'm stepping along the surface in a number of iterations based on a tolerance, getting worldspace coordinates, doing a distance, and adding all the distances up. It works but it's not the most accurate solution and I'm worried about speed.
Thanks in advance!
12 December 2011, 10:37 PM
about 1) - you can setup any attribute, who starts empty with default values in the postConstructor() of your node. I do it all the time for ramp attributes and various multi-attributes.
thisNode = self.thisMObject()
arrPlug = om.MPlug(thisNode, self.aArray)
for i in range(25):
12 December 2011, 10:49 PM
1. FYI, Multi/Array attributes are sparse arrays by definition. For example, if you were to access a given element of that array attribute through MPlug::elementByLogicalIndex(i) you would have instantiated that element and your physical array would be length 1, but logical array would be length i.
With regards to your actual question, the way I would either associate the firstRun data as part of whatever method you use to create your node (script/command) or attach it as part of the MPxNode::postConstructor method.
2. Can you show what your attributeAffects is? I would create the attributeAffects at the parent level. So if you have:
I would do the equivalent of attributeAffects( myNode.arrayAttr, myNode.pointAttr ). Is it possible that you're doing attributeAffects on each child attr?
3. I ran into something similar with MFnNurbsCurve where I wanted the inverse of findParamFromLength(). But basically neither exists. In my case I wound up iterating until I converged on the point I was looking for. Looking at MFnNurbsSurface, I think your approach is basically it. If the API were exposed to do this, I suspect it would wind up doing the same thing, just with a few less levels of indirection.
12 December 2011, 06:02 AM
Thanks for the quick replies!
@Azrail: I'd thought to do it this way but the plug's name() in postConstructor returned only the partial attribute name and not the full name of the node plus attribute. I'll give that a go tomorrow, though!
Can you show what your attributeAffects is? I would create the attributeAffects at the parent level. ...... I would do the equivalent of attributeAffects( myNode.arrayAttr, myNode.pointAttr ). Is it possible that you're doing attributeAffects on each child attr?
That's what I thought, too. I've been doing my attributeAffects on the parent, like:
That works for single attributes like kFloat or kDouble, but for the point attributes it's different. If I connect child attribute .outputPositionX to something, the compute's plug is always equal to outputPositionX and not the parent outputPosition. Is that expected behavior?
I ran into something similar with MFnNurbsCurve where I wanted the inverse of findParamFromLength(). But basically neither exists. In my case I wound up iterating until I converged on the point I was looking for. Looking at MFnNurbsSurface, I think your approach is basically it.
Okay... Just checking. Is there an optimized way to do this, though, apart from rewriting in C++? I had a crazy idea about squared distances but it didn't pan out. :)
12 December 2011, 08:18 PM
To be honest, it's been a while since I've dealt with point attributes, so I don't recall what the expected behavior is. But given that it is doing that, couldn't you just do something like:
if( plug == mPointAttr || plug == mPointAttrX || plug == mPointAttrY || plug == mPointAttrZ )
// The point changed, compute.
I'm not aware of anything that's more efficient than what you're already doing for computing the param length.
12 December 2011, 03:14 PM
@Keilun The way the point attributes are created you only get back the parent and none of the children, as I understood it. For the moment I made kDouble array attributes for the various X/Y/Z's I needed and that worked a treat. I might go back to figure out the pointAttrs later, though; I'm sure I just missed something or misread documentation.
Thanks again-- by end of day Friday the node was behaving wonderfully. :D
12 December 2011, 03:35 PM
Right, but I believe you can browse the children of that parent attr to get the child attrs through MFnCompoundAttribute. Good to hear you got it working though. I tend to just build out my own attributes like you did too. I'm more confident that they'll work in those cases.
12 December 2011, 03:35 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.