Python API 2.0 Reference
python/api1/py1ArrayAttrBlenderNode.py
1 #-
2 # ==========================================================================
3 # Copyright (C) 2021 Autodesk, Inc. and/or its licensors. All
4 # rights reserved.
5 #
6 # The coded instructions, statements, computer programs, and/or related
7 # material (collectively the "Data") in these files contain unpublished
8 # information proprietary to Autodesk, Inc. ("Autodesk") and/or its
9 # licensors, which is protected by U.S. and Canadian federal copyright
10 # law and by international treaties.
11 #
12 # The Data is provided for use exclusively by You. You have the right
13 # to use, modify, and incorporate this Data into other products for
14 # purposes authorized by the Autodesk software license agreement,
15 # without fee.
16 #
17 # The copyright notices in the Software and this entire statement,
18 # including the above license grant, this restriction and the
19 # following disclaimer, must be included in all copies of the
20 # Software, in whole or in part, and all derivative works of
21 # the Software, unless such copies or derivative works are solely
22 # in the form of machine-executable object code generated by a
23 # source language processor.
24 #
25 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
26 # AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED
27 # WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF
28 # NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
29 # PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR
30 # TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS
31 # BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL,
32 # DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK
33 # AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY
34 # OR PROBABILITY OF SUCH DAMAGES.
35 #
36 # ==========================================================================
37 #+
38 
39 #
40 # Autodesk Script File
41 # MODIFY THIS AT YOUR OWN RISK
42 #
43 # Creation Date: 27 May 2021
44 #
45 
46 """
47  DESCRIPTION:
48 
49  Implements the dependency graph node "spArrayAttrBlend".
50 
51  This plug-in is an example of a user-defined dependency graph node.
52  It takes 2 array inputs and it computes an array output
53  where each output value is the average of the 2 corresponding inputs values.
54  A weight parameter controls how much of input A vs input B is taken into
55  account in the output computation
56 
57  // Create a spArrayAttrBlend connected to a cube translation
58  createNode spArrayAttrBlend;
59  polyCube;
60 
61  connectAttr spArrayAttrBlend1.output[0] pCube1.tx;
62  connectAttr spArrayAttrBlend1.output[1] pCube1.ty;
63  connectAttr spArrayAttrBlend1.output[2] pCube1.tz;
64 
65  // Modify input parameters to affect the cube position
66  setAttr spArrayAttrBlend1.weight 1; // Output is driven 100% by inputB
67  setAttr spArrayAttrBlend1.inputB[1] 10; // will feed 10 to pCube1.ty
68 
69 """
70 
71 import maya.OpenMaya as OpenMaya
72 import maya.OpenMayaMPx as OpenMayaMPx
73 
74 kPluginNodeTypeName = "spArrayAttrBlend"
75 kPluginNodeId = OpenMaya.MTypeId(0x0008005A)
76 
77 
78 # Node definition
79 class spArrayAttrBlend(OpenMayaMPx.MPxNode):
80 
81  # Node Type Attributes
82  aInputA = OpenMaya.MObject()
83  aInputB = OpenMaya.MObject()
84  aWeight = OpenMaya.MObject()
85  aOutput = OpenMaya.MObject()
86 
87 
88  def __init__(self):
89  OpenMayaMPx.MPxNode.__init__(self)
90 
91 
92  def getInputValue( data, attribute, logicalIndex ):
93  """
94  Helper method that extract an element value from the datablock for a specified
95  array attribute
96  """
97  # This code was extracted from the compute method because it needs to be executed twice
98  # at each evaluation (once for each input)
99 
100  arrayDataHandle = data.inputArrayValue( attribute )
101  try:
102  arrayDataHandle.jumpToElement( logicalIndex )
103  value = arrayDataHandle.inputValue().asFloat()
104  except:
105  # Extracting Attribute default value
106  # Code is compled because MFnNumericAttribute returns its result through a reference
107  # parameter which ends up being very complicated to handle in Python API1
108  default_util = OpenMaya.MScriptUtil()
109  default_util.createFromDouble(0.0)
110  default_ptr = default_util.asFloatPtr()
111  OpenMaya.MFnNumericAttribute( attribute ).getDefault( default_ptr )
112  value = default_util.getFloat( default_ptr )
113 
114  return value
115 
116 
117  def compute(self, plug, data):
118  """
119  This callback gets invoked when Maya needs to retrieve the value of
120  a marked dirty plug
121  """
122 
123  # Check that the requested recompute is one of the output values
124  if (plug == spArrayAttrBlend.aOutput ):
125  if plug.isArray():
126  # full attribute is rarely queried but by returning kUnknownParameter
127  # we ensure Maya default implementation will trigger the evaluation of
128  # each element of the array plug
129  return OpenMaya.kUnknownParameter
130  else:
131  # Computing the value of one array plug element
132  logicalIndex = plug.logicalIndex()
133 
134  # Read the input values
135  A = spArrayAttrBlend.getInputValue( data, spArrayAttrBlend.aInputA, logicalIndex )
136  B = spArrayAttrBlend.getInputValue( data, spArrayAttrBlend.aInputB, logicalIndex )
137 
138  weight = data.inputValue( spArrayAttrBlend.aWeight ).asFloat()
139 
140  blendedValue = A*(1.0-weight )+B*weight
141 
142  data.outputValue(plug).setFloat( blendedValue )
143  data.setClean( plug )
144  return None
145  else:
146  return OpenMaya.kUnknownParameter
147 
148 
149  def setDependentsDirty( self, plug, plugArray ):
150  # this method is optional. It currently handles the dependence of output on inputA and inputB
151  # This approach differs from letting Maya doing the dirtying based on the MPxNode.attributeAffects
152  # because it defines a plug element to plug element relationship. MPxNode.attributeAffects usage
153  # would cause a dirtying of all the output elements even for a single input element change
154  if (plug == spArrayAttrBlend.aInputA ) or (plug == spArrayAttrBlend.aInputB ):
155  if plug.isElement():
156  logicalIndex = plug.logicalIndex()
157  thisNode = self.thisMObject()
158  outPlug = OpenMaya.MPlug( thisNode, spArrayAttrBlend.aOutput )
159  outPlug.selectAncestorLogicalIndex( logicalIndex, spArrayAttrBlend.aOutput )
160  plugArray.append(outPlug)
161 
162 
163 # creator
164 def createNodeInstance():
165  """ Maya invokes this method everytime it needs to instanciate a spArrayAttrBlend node """
166  return OpenMayaMPx.asMPxPtr( spArrayAttrBlend() )
167 
168 
169 # initializer
170 def initNodeTypeAttributes():
171  """
172  This method is invoked when spArrayAttrBlend node type gets registered
173  allowing the current plugin to register and setup attributes to the
174  new spArrayAttrBlend type
175  """
176 
177  # The MFnNumericAttribute will help in the creation of all the numerical
178  # input and output attributes
180 
181  # Setup the input attributes
182  spArrayAttrBlend.aInputA = nAttr.create("inputA", "ia", OpenMaya.MFnNumericData.kFloat, 0.2)
183  nAttr.setStorable(True)
184  nAttr.setArray( True )
185 
186  spArrayAttrBlend.aInputB = nAttr.create("inputB", "ib", OpenMaya.MFnNumericData.kFloat, 0.3)
187  nAttr.setStorable(True)
188  nAttr.setArray( True )
189 
190  spArrayAttrBlend.aWeight = nAttr.create("weight", "wt", OpenMaya.MFnNumericData.kFloat, 0.5)
191  nAttr.setStorable(True)
192  nAttr.setArray( False )
193 
194  # Setup the output attributes
195  spArrayAttrBlend.aOutput = nAttr.create("output", "out", OpenMaya.MFnNumericData.kFloat, 0.0)
196  nAttr.setStorable(False)
197  nAttr.setWritable(False)
198  nAttr.setArray( True )
199 
200  # Add the attributes to the node
201  spArrayAttrBlend.addAttribute(spArrayAttrBlend.aInputA)
202  spArrayAttrBlend.addAttribute(spArrayAttrBlend.aInputB)
203  spArrayAttrBlend.addAttribute(spArrayAttrBlend.aWeight)
204  spArrayAttrBlend.addAttribute(spArrayAttrBlend.aOutput)
205 
206  # Set the attribute dependencies
207  spArrayAttrBlend.attributeAffects(spArrayAttrBlend.aWeight, spArrayAttrBlend.aOutput)
208 
209  # The following dependencies should not be declared because they are already handled
210  # by the optional setDependentsDirty method
211  # spArrayAttrBlend.attributeAffects(spArrayAttrBlend.aInputA, spArrayAttrBlend.aOutput)
212  # spArrayAttrBlend.attributeAffects(spArrayAttrBlend.aInputB, spArrayAttrBlend.aOutput)
213 
214 
215 def initializePlugin(mobject):
216  """ This method is automatically invoked when the plugin is loaded """
217  mplugin = OpenMayaMPx.MFnPlugin(mobject, "Autodesk", "1.0", "Any")
218  try:
219  mplugin.registerNode( kPluginNodeTypeName, kPluginNodeId, createNodeInstance, initNodeTypeAttributes )
220  except:
221  sys.stderr.write( "Failed to register node: %s" % kPluginNodeTypeName )
222  raise
223 
224 
225 def uninitializePlugin(mobject):
226  """ This method is automatically invoked when the plugin is unloaded """
227  mplugin = OpenMayaMPx.MFnPlugin(mobject)
228  try:
229  mplugin.deregisterNode( kPluginNodeId )
230  except:
231  sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeTypeName )
232  raise
233