scripted/testNucleusNode.py

scripted/testNucleusNode.py
1 #-
2 # ==========================================================================
3 # Copyright (C) 2011 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 
41 This example show a custom solver at work. Two nCloth objects are created,
42 one is disconnected from the default nucleus solver, and hooked to
43 this custom solver node, which will just compute a sine wave motion on
44 the cloth in time.
45 
46 A custom solver needs to have a minimum of 3 attributes:
47 
48 -startState To be connected from the cloth object to the solver
49 -currentState To be connected from the cloth object to the solver
50 -nextState To be connected from the solver object to the cloth
51 
52 and usually a 4th attribute that is the current time.
53 
54 The idea is that when a solve is needed, the cloth object will pull on the
55 nextState attribute. At this point the solver should pull on either the
56 currentState attribute or the startState, depending on the current time.
57 Once it has the state information, the solver can extract that information,
58 solve one step, and stuff that information back into the MnCloth to
59 complete the solve.
60 
61 Below is some example code to test this plugin:
62 
63 #**************************************************************************
64 # Note: Before running this code, make sure the plugin spTestNucleusNode is loaded!
65 #**************************************************************************
66 import maya.cmds as cmds
67 import maya.mel as mel
68 def setupCustomSolverScene():
69  cmds.file( f=True, new=True )
70 
71  pPlane1 = cmds.polyPlane( w=5, h=5, sx=10, sy=10, ax=(0,1,0), cuv=2, ch=1 )
72  cmds.move( -10, 0, 0, r=True )
73  mel.eval( 'createNCloth 0' )
74 
75  pPlane2 = cmds.polyPlane( w=5, h=5, sx=10, sy=10, ax=(0,1,0), cuv=2, ch=1 )
76  mel.eval( 'createNCloth 0' )
77 
78  # Hookup plane2 (the cloth object created for plane2 is named nClothShape2) to our custom solver instead.
79 
80  # First, disconnect it from the default nucleus solver:
81  cmds.disconnectAttr( 'nClothShape2.currentState', 'nucleus1.inputActive[1]' )
82  cmds.disconnectAttr( 'nClothShape2.startState', 'nucleus1.inputActiveStart[1]' )
83  cmds.disconnectAttr( 'nucleus1.outputObjects[1]', 'nClothShape2.nextState' )
84 
85  # create our custom solver:
86  cmds.createNode( 'spTestNucleusNode' )
87 
88  # Hookup plane2 to our custom solver:
89  cmds.connectAttr( 'spTestNucleusNode1.nextState[0]', 'nClothShape2.nextState' )
90  cmds.connectAttr( 'nClothShape2.currentState', 'spTestNucleusNode1.currentState[0]' )
91  cmds.connectAttr( 'nClothShape2.startState', 'spTestNucleusNode1.startState[0]' )
92  cmds.connectAttr( 'time1.outTime', 'spTestNucleusNode1.currentTime' )
93 
94 """
95 
96 import sys, math
97 import maya.OpenMaya as OpenMaya
98 import maya.OpenMayaMPx as OpenMayaMPx
99 import maya.OpenMayaFX as OpenMayaFX
100 
101 class testNucleusNode(OpenMayaMPx.MPxNode):
102  kPluginNodeName = "spTestNucleusNode"
103  kPluginNodeId = OpenMaya.MTypeId(0x85006)
104  startState = OpenMaya.MObject()
105  currentState = OpenMaya.MObject()
106  nextState = OpenMaya.MObject()
107  currentTime = OpenMaya.MObject()
108 
109  def __init__(self):
110  OpenMayaMPx.MPxNode.__init__(self)
111 
112  def compute(self, plug, data):
113  if plug == testNucleusNode.nextState:
114  if plug.isArray():
115  # don't support evaluation of the whole array plug, only its elements
116  return OpenMaya.kUnknownParameter
117  logicalIndex = plug.logicalIndex()
118  # get the value of the currentTime
119  currTime = data.inputValue(testNucleusNode.currentTime).asTime()
120  # pull on start state or current state depending on the current time.
121  if currTime.value() <= 0.0:
122  multiDataHandle = data.inputArrayValue(testNucleusNode.startState)
123  multiDataHandle.jumpToElement( logicalIndex )
124  inputData = multiDataHandle.inputValue().data()
125  else:
126  multiDataHandle = data.inputArrayValue(testNucleusNode.currentState)
127  multiDataHandle.jumpToElement( logicalIndex )
128  inputData = multiDataHandle.inputValue().data()
129 
130  inputNData = OpenMayaFX.MFnNObjectData(inputData)
131  nObj = inputNData.getClothObjectPtr()
132 
133  points = OpenMaya.MFloatPointArray()
134  nObj.getPositions(points)
135  for ii in range( points.length() ):
136  points[ii].y = math.sin( points[ii].x + currTime.value()*4.0*(3.1415/180.0) )
137  nObj.setPositions(points)
138 
139  data.setClean(plug)
140  elif plug == testNucleusNode.currentState:
141  data.setClean(plug)
142  elif plug == testNucleusNode.startState:
143  data.setClean(plug)
144  else:
145  return OpenMaya.kUnknownParameter
146 
147  @staticmethod
148  def creator():
149  return OpenMayaMPx.asMPxPtr( testNucleusNode() )
150 
151  @staticmethod
152  def initializer():
154 
155  testNucleusNode.startState = tAttr.create("startState", "sst", OpenMaya.MFnData.kNObject)
156  tAttr.setWritable(True)
157  tAttr.setStorable(True)
158  tAttr.setHidden(True)
159  tAttr.setArray(True)
160 
161  testNucleusNode.currentState = tAttr.create("currentState", "cst", OpenMaya.MFnData.kNObject)
162  tAttr.setWritable(True)
163  tAttr.setStorable(True)
164  tAttr.setHidden(True)
165  tAttr.setArray(True)
166 
167  testNucleusNode.nextState = tAttr.create("nextState", "nst", OpenMaya.MFnData.kNObject)
168  tAttr.setWritable(True)
169  tAttr.setStorable(True)
170  tAttr.setHidden(True)
171  tAttr.setArray(True)
172 
173  uniAttr = OpenMaya.MFnUnitAttribute()
174  testNucleusNode.currentTime = uniAttr.create( "currentTime", "ctm" , OpenMaya.MFnUnitAttribute.kTime, 0.0 )
175 
176  testNucleusNode.addAttribute(testNucleusNode.startState)
177  testNucleusNode.addAttribute(testNucleusNode.currentState)
178  testNucleusNode.addAttribute(testNucleusNode.nextState)
179  testNucleusNode.addAttribute(testNucleusNode.currentTime)
180 
181  testNucleusNode.attributeAffects(testNucleusNode.startState, testNucleusNode.nextState)
182  testNucleusNode.attributeAffects(testNucleusNode.currentState, testNucleusNode.nextState)
183  testNucleusNode.attributeAffects(testNucleusNode.currentTime, testNucleusNode.nextState)
184 
185 # initialize the script plug-in
186 def initializePlugin(mobject):
187  mplugin = OpenMayaMPx.MFnPlugin(mobject)
188  try:
189  mplugin.registerNode( testNucleusNode.kPluginNodeName, testNucleusNode.kPluginNodeId, testNucleusNode.creator, testNucleusNode.initializer )
190  except:
191  sys.stderr.write( "Failed to register node: %s" % testNucleusNode.kPluginNodeName )
192  raise
193 
194 # uninitialize the script plug-in
195 def uninitializePlugin(mobject):
196  mplugin = OpenMayaMPx.MFnPlugin(mobject)
197  try:
198  mplugin.deregisterNode( testNucleusNode.kPluginNodeId )
199  except:
200  sys.stderr.write( "Failed to deregister node: %s" % testNucleusNode.kPluginNodeName )
201  raise
202