Python API 2.0 Reference
python/api1/py1NucleusNodeTest.py
1 from __future__ import division
2 
3 #-
4 # ==========================================================================
5 # Copyright (C) 2011 Autodesk, Inc. and/or its licensors. All
6 # rights reserved.
7 #
8 # The coded instructions, statements, computer programs, and/or related
9 # material (collectively the "Data") in these files contain unpublished
10 # information proprietary to Autodesk, Inc. ("Autodesk") and/or its
11 # licensors, which is protected by U.S. and Canadian federal copyright
12 # law and by international treaties.
13 #
14 # The Data is provided for use exclusively by You. You have the right
15 # to use, modify, and incorporate this Data into other products for
16 # purposes authorized by the Autodesk software license agreement,
17 # without fee.
18 #
19 # The copyright notices in the Software and this entire statement,
20 # including the above license grant, this restriction and the
21 # following disclaimer, must be included in all copies of the
22 # Software, in whole or in part, and all derivative works of
23 # the Software, unless such copies or derivative works are solely
24 # in the form of machine-executable object code generated by a
25 # source language processor.
26 #
27 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
28 # AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED
29 # WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF
30 # NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
31 # PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE, OR
32 # TRADE PRACTICE. IN NO EVENT WILL AUTODESK AND/OR ITS LICENSORS
33 # BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL,
34 # DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK
35 # AND/OR ITS LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY
36 # OR PROBABILITY OF SUCH DAMAGES.
37 #
38 # ==========================================================================
39 #+
40 
41 """
42 
43 This example show a custom solver at work. Two nCloth objects are created,
44 one is disconnected from the default nucleus solver, and hooked to
45 this custom solver node, which will just compute a sine wave motion on
46 the cloth in time.
47 
48 A custom solver needs to have a minimum of 3 attributes:
49 
50 -startState To be connected from the cloth object to the solver
51 -currentState To be connected from the cloth object to the solver
52 -nextState To be connected from the solver object to the cloth
53 
54 and usually a 4th attribute that is the current time.
55 
56 The idea is that when a solve is needed, the cloth object will pull on the
57 nextState attribute. At this point the solver should pull on either the
58 currentState attribute or the startState, depending on the current time.
59 Once it has the state information, the solver can extract that information,
60 solve one step, and stuff that information back into the MnCloth to
61 complete the solve.
62 
63 Below is some example code to test this plugin:
64 
65 #**************************************************************************
66 # Note: Before running this code, make sure the plugin spTestNucleusNode is loaded!
67 #**************************************************************************
68 import maya.cmds as cmds
69 import maya.mel as mel
70 def setupCustomSolverScene():
71  cmds.file( f=True, new=True )
72 
73  pPlane1 = cmds.polyPlane( w=5, h=5, sx=10, sy=10, ax=(0,1,0), cuv=2, ch=1 )
74  cmds.move( -10, 0, 0, r=True )
75  mel.eval( 'createNCloth 0' )
76 
77  pPlane2 = cmds.polyPlane( w=5, h=5, sx=10, sy=10, ax=(0,1,0), cuv=2, ch=1 )
78  mel.eval( 'createNCloth 0' )
79 
80  # Hookup plane2 (the cloth object created for plane2 is named nClothShape2) to our custom solver instead.
81 
82  # First, disconnect it from the default nucleus solver:
83  cmds.disconnectAttr( 'nClothShape2.currentState', 'nucleus1.inputActive[1]' )
84  cmds.disconnectAttr( 'nClothShape2.startState', 'nucleus1.inputActiveStart[1]' )
85  cmds.disconnectAttr( 'nucleus1.outputObjects[1]', 'nClothShape2.nextState' )
86 
87  # create our custom solver:
88  cmds.createNode( 'spTestNucleusNode' )
89 
90  # Hookup plane2 to our custom solver:
91  cmds.connectAttr( 'spTestNucleusNode1.nextState[0]', 'nClothShape2.nextState' )
92  cmds.connectAttr( 'nClothShape2.currentState', 'spTestNucleusNode1.currentState[0]' )
93  cmds.connectAttr( 'nClothShape2.startState', 'spTestNucleusNode1.startState[0]' )
94  cmds.connectAttr( 'time1.outTime', 'spTestNucleusNode1.currentTime' )
95 
96 """
97 
98 from builtins import range
99 import sys, math
100 import maya.OpenMaya as OpenMaya
101 import maya.OpenMayaMPx as OpenMayaMPx
102 import maya.OpenMayaFX as OpenMayaFX
103 
104 class testNucleusNode(OpenMayaMPx.MPxNode):
105  kPluginNodeName = "spTestNucleusNode"
106  kPluginNodeId = OpenMaya.MTypeId(0x00085007)
107  startState = OpenMaya.MObject()
108  currentState = OpenMaya.MObject()
109  nextState = OpenMaya.MObject()
110  currentTime = OpenMaya.MObject()
111 
112  def __init__(self):
113  OpenMayaMPx.MPxNode.__init__(self)
114 
115  def compute(self, plug, data):
116  if plug == testNucleusNode.nextState:
117  if plug.isArray():
118  # don't support evaluation of the whole array plug, only its elements
119  return OpenMaya.kUnknownParameter
120  logicalIndex = plug.logicalIndex()
121  # get the value of the currentTime
122  currTime = data.inputValue(testNucleusNode.currentTime).asTime()
123  # pull on start state or current state depending on the current time.
124  if currTime.value() <= 0.0:
125  multiDataHandle = data.inputArrayValue(testNucleusNode.startState)
126  multiDataHandle.jumpToElement( logicalIndex )
127  inputData = multiDataHandle.inputValue().data()
128  else:
129  multiDataHandle = data.inputArrayValue(testNucleusNode.currentState)
130  multiDataHandle.jumpToElement( logicalIndex )
131  inputData = multiDataHandle.inputValue().data()
132 
133  inputNData = OpenMayaFX.MFnNObjectData(inputData)
134  nObj = inputNData.getClothObjectPtr()
135 
136  points = OpenMaya.MFloatPointArray()
137  nObj.getPositions(points)
138  for ii in range( points.length() ):
139  points[ii].y = math.sin( points[ii].x + currTime.value()*4.0*(3.1415/180.0) )
140  nObj.setPositions(points)
141 
142  data.setClean(plug)
143  elif plug == testNucleusNode.currentState:
144  data.setClean(plug)
145  elif plug == testNucleusNode.startState:
146  data.setClean(plug)
147  else:
148  return OpenMaya.kUnknownParameter
149 
150  @staticmethod
151  def creator():
152  return OpenMayaMPx.asMPxPtr( testNucleusNode() )
153 
154  @staticmethod
155  def initializer():
157 
158  testNucleusNode.startState = tAttr.create("startState", "sst", OpenMaya.MFnData.kNObject)
159  tAttr.setWritable(True)
160  tAttr.setStorable(True)
161  tAttr.setHidden(True)
162  tAttr.setArray(True)
163 
164  testNucleusNode.currentState = tAttr.create("currentState", "cst", OpenMaya.MFnData.kNObject)
165  tAttr.setWritable(True)
166  tAttr.setStorable(True)
167  tAttr.setHidden(True)
168  tAttr.setArray(True)
169 
170  testNucleusNode.nextState = tAttr.create("nextState", "nst", OpenMaya.MFnData.kNObject)
171  tAttr.setWritable(True)
172  tAttr.setStorable(True)
173  tAttr.setHidden(True)
174  tAttr.setArray(True)
175 
176  uniAttr = OpenMaya.MFnUnitAttribute()
177  testNucleusNode.currentTime = uniAttr.create( "currentTime", "ctm" , OpenMaya.MFnUnitAttribute.kTime, 0.0 )
178 
179  testNucleusNode.addAttribute(testNucleusNode.startState)
180  testNucleusNode.addAttribute(testNucleusNode.currentState)
181  testNucleusNode.addAttribute(testNucleusNode.nextState)
182  testNucleusNode.addAttribute(testNucleusNode.currentTime)
183 
184  testNucleusNode.attributeAffects(testNucleusNode.startState, testNucleusNode.nextState)
185  testNucleusNode.attributeAffects(testNucleusNode.currentState, testNucleusNode.nextState)
186  testNucleusNode.attributeAffects(testNucleusNode.currentTime, testNucleusNode.nextState)
187 
188 # initialize the script plug-in
189 def initializePlugin(mobject):
190  mplugin = OpenMayaMPx.MFnPlugin(mobject)
191  try:
192  mplugin.registerNode( testNucleusNode.kPluginNodeName, testNucleusNode.kPluginNodeId, testNucleusNode.creator, testNucleusNode.initializer )
193  except:
194  sys.stderr.write( "Failed to register node: %s" % testNucleusNode.kPluginNodeName )
195  raise
196 
197 # uninitialize the script plug-in
198 def uninitializePlugin(mobject):
199  mplugin = OpenMayaMPx.MFnPlugin(mobject)
200  try:
201  mplugin.deregisterNode( testNucleusNode.kPluginNodeId )
202  except:
203  sys.stderr.write( "Failed to deregister node: %s" % testNucleusNode.kPluginNodeName )
204  raise
205