Maya's Plus Minus Average Node Explained From a Rigging Perspective. Python

General / 14 December 2021

The Autodesk documentation on the plus minus average node is atrocious, so I though I would make some notes about it in case somebody else is also confused.

Also, these nodes are frequently used in rigging, probably more than they are used in shading networks, but they are written for shading networks and the documentation assumes that is how you are using them so they can be confusing to look at for their rigging potential.  Just for the record I think Autodesk should make another class of math nodes that are not shading-centric but they don't listen to me.

Sorry in advance for this really long post, but there is a lot to know about how to use this node and in typical Autodesk fashion most of what you need to know is about how flawed the tool is.

First let's talk about how it works.  And then I will walk through the setup.

The input values that you plug into this node can be added, subtracted or averaged and the output can be used for whatever purpose you like.  That's fairly straight forward but knowing how those values get plugged in and how they work once they are there is where the confusion sets in.   There are 3 sets of inputs available on this node that offer the ability to process 1 list of numbers, 2 lists of numbers or 3 lists of numbers.  All of the numbers in the list will have the operation performed on them. So you might have values in 1D of [1, 2, 3]  and the operation is Sum the output would be 6.  You may have a 2D list [[1, 2, 3,], [4, 5, 6]]  if the operation was Sum then you would have an output of 6 and 15.

So again, it can take either single dimension inputs which appears as (input 1D), double input dimensions (input 2D),  or triple input dimensions (input 3D).  It could conceivably take all three if you like since each of these inputs whether a single, double or triple are their own distinct lists with their own distinct outputs.

The designations for the different inputs are:

.input1D[num], .input2D[num], .input3D[num] where num is the position of numbers in the list to be added.

So if you wanted to add the number 1 plus the number 2 you would write that like this:

cmds.setAttr('plusMinusAverage1' + '.input1D[0]', 1)

# the way this would read is: set an attribute on the plusMinusAverage1 node, the attribute is the first position in the input list designated with the index position [0] and the value of that entry is 1.

cmds.setAttr('plusMinusAverage1' + '.input1D[1]', 2)

# the way this would read is: set an attribute on the plusMinusAverage1 node, the attribute is the first position in the input list designated with the index position [1] and the value of that entry is 2.

Now lets look at setting up a plusMinusAverageNode manually.

Open the node editor under "Windows"  although you can work with this object in the hypershade the node editor works better for utility nodes.

Create a plus minus average node.   You can do this by clicking in the Node Editor window and hitting the tab button, then you can type in 'plus', it will narrow your search and then you can click the node you want and hit enter to create.

Select that node and view it in your attribute editor.  You will see that there are drop down menus.  All of the business for this node is under Plus-Minus-Average Attributes.  Open that.  The first thing you will see is the operation.  Its default is "Sum" you can set it to "Subtract" or "Average" and  "No operation"  That's fairly self explanatory, you can change the operation of the node by changing that value.

Next set of drop downs are the Input 1D, input 2D and input 3D.  Open these up and you will see that there are no inputs available yet.  There is also an incongruity between the field for the Input 1D and the other inputs.  The Input 1D area is a large inert field with no buttons to interact with it.  You can't drag anything into the field, you can't enter anything, it's useless as it is.  But the other inputs allow you to click buttons that add new items.  Go ahead and add a new item to either the 2D or the 3D. "The Add New Item" creates lists of inputs that can be directly manipulated through the attribute editor, you can also make new connections via the familiar checker button next to the fields and you can make manual connections via the Node Editor, the Hypershade or the Connection editor by middle mouse dragging connections.

Now understand this, there is no functional reason for the 1D field.  In fact there is no functional reason for the 2D either.  Each channel of the 3D input has a corresponding 3D output.  Each of the 3 channels operate independently and don't effect each other so if you wanted to just calculate a single list of values you could just use one channel of the Input 3D.  I don't know exactly why they have the 1D and 2D inputs.  I imagine there is a slight computational savings to use the 1D if you are only calculating a single value.  However that doesn't explain the wildly different treatment of the 1D input.  Overall this is a really poorly written tool.  What would make this a really smart tool is if you could dynamically assign any number of input dimensions.  Why limit it to 3 and why treat any number of dimensions different from any other?  Why?  because Autodesk... that's why.

Whatever, I'll still tell you how to use the 1D, but the fact that a single channel of the 3D does the same thing as the 1D at least helps illuminate the nature of this node.

So, make another plus minus average node in the Node Editor window.

Now click on the little 3 oblong button icon in the upper right hand corner of each of the nodes.  Click 3 times on the button to expand the node completely. Now you will see the channels for the nodes.

MMD the output 1D of one node into the input 1D of the second node.  Now look in the attribute editor for the node that is getting the input and you will see that it now has an input that is being generated by a connection (yellow block) and the value is 0.  Now look back at the node editor at the node receiving the input.  There is now a second value field that magically appeared when you added the first.  It can also take an input connection, so you can go on making connections.  But what if you wanted a set of values to be static or not derived from a connection?  Go ahead and try to figure it out...  I'm waiting... still waiting...  Ha!  You can't do it without code.  Isn't that bullshit? We'll get to how you do that in a bit, but lets now use the 2D input/output to manually set up a connection.

Select the firstPlusMinusAverage node and view it in your attribute editor.

Hit the "Add New Item" button under the Input 2D drop down. The fields for the node are made available to you.

Click in the the first channel in the Input2D[0] to 5.  BTW this first column is the "x" channel in code but has no decoration here.

Go back to the node editor and middle mouse drag Output 2Dx from the first plus minus average node into the Input 2Dx of the second plus minus average node.

Now select the second plus minus average node and view it in the attribute editor.  You will see that the Input 2D has the yellow filed signifying it is connected and the value is 5.

Click the "Add New Item" button and you will get another set of fields.

Select the first plus minus average node and in the attribute editor.

Change the value in the second column of Input to 10 (this second column is the "y" channel in code but has no decoration here)

Go back to the node editor and from the first plus minus average node drag Output 2Dy into the Input 2D[1], Input 2Dx of the second plus minus average node

Select the second plus minus average node receiving the inputs, view it in the attribute editor and you will now see that there are two connected inputs, one with a value of 5, the other 10.

You will see that there is nowhere to view the output for this node which I think is dumb but whatever.

Create a sphere and it will automatically be loaded into your Node Editor.  There are 3 nodes to this shape, the shape node itself, the history node and the transform.

Middle mouse drag the Output 2D, Output 2Dx into the Translate Y of the transform node for the sphere you just created and you will now see that shape jump up in your scene.

You can now control this shape's y position with the first plus minus average node inputs.

Pretty cool hua?

Now lets move on to the code you would use to create these nodes and setup inputs and outputs for them.

You create a plusMinusAverage Node  like this:

SomePlusMinusAverageNode = cmds.shadingNode('plusMinusAverage', asUtility = True, name ='somethingPlusMinusAverageNode')

The code to change the operation for the node is:

#this changes the operation to subtract cmds.setAttr(SomePlusMinusAverageNode + '.operation', 2)

Note that the value passed is an enum, with 1 for add, 2 for subtract, 3 for average and 0 for none

We will be manipulating the 1D input here.  Before you can do anything with the 1D field you have to first create a field.

Here is the code to create an entry field without a connection:

cmds.setAttr(SomePlusMinusAverageNode + '.input1D[0]', 0)

Now you can change that value manually to whatever you want.  That's how you can create a static field, or one that is changed with code.

Add another value as this operation is currently just outputting the single value you have entered.

cmds.setAttr(SomePlusMinusAverageNode + '.input1D[1]', 5)

The way that this now works is that the operation will be performed on every value in the list of the attribute editor.  The values appear as a vertical list in the form:

Input 1D[0]

Input 1D[1]

and so on...

This same logic follows for the 2D and 3D Inputs.  2D inputs are simply two 1D inputs and 3D inputs are three 1D inputs.  You can think of them as separate lists in the multi D inputs.

There is an additional input value for the 2D and 3D inputs that designates which "dimension" the value should be entered into.

This is setting the 3DX input to 5:

cmds.setAttr(SomePlusMinusAverageNode + '.input3D[1]' + '.input3Dx', 5)

To connect the output of a plus minus average node you simply have to connect the output of the specific channel you have manipulated to whatever input you want it to drive.

cmds.sphere(name = 'testSphere')

cmds.connectAttr(SomePlusMinusAverageNode + '.output1D', 'testSphere' + '.translateY' )

To connect the 3D output it would look like this:
cmds.connectAttr(SomePlusMinusAverageNode + '.output3Dx ', 'testSphere' + '.translateY' )

That's it!  Now you should know the different ways to create and manipulate a plus minus average node and how to use it.!