Python API 2.0 Reference
python/api1/py1RockingTransform.py
1 ########################################################################
2 # DESCRIPTION:
3 #
4 # Produces the custom transform node "spRockingTransformNode".
5 #
6 # This plug-in implements an example custom transform that
7 # can be used to perform a rocking motion around the X axis.
8 # Geometry of any rotation can be made a child of this transform
9 # to demonstrate the effect.
10 #
11 # The plug-in contains two pieces:
12 #
13 # 1. The custom transform node - rockingTransformNode
14 # 2. The custom transformation matrix - rockingTransformMatrix
15 #
16 # These classes are used together in order to implement the
17 # rocking motion. Note that the rock attribute is stored outside
18 # of the regular transform attributes.
19 #
20 # To use, execute the following commands:
21 #
22 # import maya.cmds
23 # maya.cmds.loadPlugin("rockingTransform.py")
24 # maya.cmds.file(f=True,new=True)
25 # maya.cmds.polyPlane()
26 # maya.cmds.select("pPlane1",r=True)
27 # maya.cmds.rotate(-15,-15,-15,r=True,ws=True)
28 # maya.cmds.createNode("spRockingTransform")
29 # maya.cmds.parent("pPlane1","spRockingTransform1")
30 # maya.cmds.setAttr("spRockingTransform1.rockx",55)
31 #
32 ########################################################################
33 
34 import maya.OpenMaya as OpenMaya
35 import maya.OpenMayaMPx as OpenMayaMPx
36 import math
37 import sys
38 
39 kRockingTransformPluginName = "spRockingTransform"
40 kRockingTransformNodeName = "spRockingTransformNode"
41 kRockingTransformNodeID = OpenMaya.MTypeId(0x87014)
42 kRockingTransformMatrixID = OpenMaya.MTypeId(0x87015)
43 
44 # keep track of instances of rockingTransformMatrix to get around script limitation
45 # with proxy classes of base pointers that actually point to derived
46 # classes
47 kTrackingDictionary = {}
48 
49 
50 class rockingTransformMatrix(OpenMayaMPx.MPxTransformationMatrix):
51 
52  def __init__(self):
53  OpenMayaMPx.MPxTransformationMatrix.__init__(self)
54  kTrackingDictionary[OpenMayaMPx.asHashable(self)] = self
55  self.rockXValue = 0.0
56 
57  def __del__(self):
58  del kTrackingDictionary[OpenMayaMPx.asHashable(self)]
59 
60  def setRockInX(self,rockingValue):
61  self.rockXValue = rockingValue
62 
63  def getRockInX(self):
64  return self.rockXValue
65 
66  def asMatrix(self,percent=None):
67  """
68  Find the new matrix and return it
69  """
70  if percent == None:
71  matrix = OpenMayaMPx.MPxTransformationMatrix.asMatrix(self)
73  quat = self.rotation()
74  rockingValue = self.getRockInX()
75  newTheta = math.radians( rockingValue )
76  quat.setToXAxis( newTheta )
77  tm.addRotationQuaternion( quat.x, quat.y, quat.z, quat.w, OpenMaya.MSpace.kTransform )
78  return tm.asMatrix()
79  else:
80  m = OpenMayaMPx.MPxTransformationMatrix(self)
81  #
82  trans = m.translation()
83  rotatePivotTrans = m.rotatePivot()
84  scalePivotTrans = m.scalePivotTranslation()
85  trans = trans * percent
86  rotatePivotTrans = rotatePivotTrans * percent
87  scalePivotTrans = scalePivotTrans * percent
88  m.translateTo(trans)
89  m.setRotatePivot( rotatePivotTrans )
90  m.setScalePivotTranslation( scalePivotTrans )
91  #
92  quat = self.rotation()
93  rockingValue = self.getRockInX()
94  newTheta = math.radians( rockingValue )
95 
96  quat.setToXAxis( newTheta )
97  m.rotateBy( quat )
98  eulerRotate = m.eulerRotation()
99  m.rotateTo( eulerRotate * percent, OpenMaya.MSpace.kTransform )
100  #
101  s = self.scale( OpenMaya.MSpace.kTransform )
102  s.x = 1.0 + ( s.x - 1.0 ) * percent
103  s.y = 1.0 + ( s.y - 1.0 ) * percent
104  s.z = 1.0 + ( s.z - 1.0 ) * percent
105  m.scaleTo( s, OpenMaya.MSpace.kTransform )
106  #
107  return m.asMatrix()
108 
109 
110 class rockingTransformNode(OpenMayaMPx.MPxTransform):
111  aRockInX = OpenMaya.MObject()
112  aCachedRock = OpenMaya.MObject()
113 
114  def __init__(self, transform=None):
115  if transform is None:
116  OpenMayaMPx.MPxTransform.__init__(self)
117  else:
118  OpenMayaMPx.MPxTransform.__init__(self, transform)
119  self.rockXValue = 0.0
120 
121  def createTransformationMatrix(self):
122  return OpenMayaMPx.asMPxPtr( rockingTransformMatrix() )
123 
124  def className(self):
125  return kRockingTransformNodeName
126 
127  #----------------------------------------------------------------------
128  def computeLocalTransformation(self, mtx, data):
129 
130  rockInXData = data.inputValue( self.aRockInX )
131  rockInX = rockInXData.asDouble()
132 
133  try:
134  # mtx is of type 'MPxTransformationMatrix'. Use kTrackingDictionary
135  # to retrieve the actual assocaited type 'rockingTransformMatrix'
136  ltm = kTrackingDictionary[OpenMayaMPx.asHashable(mtx)]
137 
138  # Update the custom transformation matrix to the right rock value.
139  ltm.setRockInX(rockInX)
140 
141  except Exception as ex:
142  print('rockingTransform computeLocalTransformation error: %s' % str(ex))
143 
144  return OpenMayaMPx.MPxTransform.computeLocalTransformation(self, mtx, data)
145 
146  #----------------------------------------------------------------------
147  def compute(self, plug, data):
148 
149  if plug.isNull():
150  return OpenMayaMPx.MPxTransform.compute(self, plug, data)
151 
152  if ( (plug == self.matrix)
153  or (plug == self.inverseMatrix)
154  or (plug == self.worldMatrix)
155  or (plug == self.worldInverseMatrix)
156  or (plug == self.parentMatrix)
157  or (plug == self.parentInverseMatrix) ):
158 
159  try:
160  ltm = self.getRockingTransformationMatrix()
161  if ltm is not None:
162  self.computeLocalTransformation(ltm, data)
163 
164  except Exception as ex:
165  print('rockingTransform Compute error: %s' % str(ex))
166 
167  return OpenMayaMPx.MPxTransform.compute(self, plug, data)
168 
169  #----------------------------------------------------------------------
170  def validateAndSetValue(self, plug, handle):
171  if not plug.isNull():
172  if plug == self.aRockInX:
173  block = self._forceCache()
174  rock_handle = block.outputValue(plug)
175 
176  # Update our new rock in x value
177  rockInX = handle.asDouble()
178  rock_handle.setDouble(rockInX)
179 
180  # Update the custom transformation matrix to the
181  # right value.
182  ltm = self.getRockingTransformationMatrix()
183  if ltm is not None:
184  ltm.setRockInX(rockInX)
185 
186  rock_handle.setClean()
187 
188  # Mark the matrix as dirty so that DG information
189  # will update.
190  self._dirtyMatrix()
191 
192  OpenMayaMPx.MPxTransform.validateAndSetValue(self, plug, handle)
193 
194  #----------------------------------------------------------------------
195  def getRockingTransformationMatrix(self):
196  baseXform = self.transformationMatrixPtr()
197  return kTrackingDictionary[OpenMayaMPx.asHashable(baseXform)]
198 
199 
200 # create/initialize node and matrix
201 def matrixCreator():
202  return OpenMayaMPx.asMPxPtr( rockingTransformMatrix() )
203 
204 def nodeCreator():
205  return OpenMayaMPx.asMPxPtr( rockingTransformNode() )
206 
207 def nodeInitializer():
209 
210  rockingTransformNode.aRockInX = numFn.create("RockInX", "rockx", OpenMaya.MFnNumericData.kDouble, 0.0)
211 
212  numFn.setKeyable(True)
213  numFn.setAffectsWorldSpace(True)
214 
215  rockingTransformNode.addAttribute(rockingTransformNode.aRockInX)
216  rockingTransformNode.mustCallValidateAndSet(rockingTransformNode.aRockInX)
217  return
218 
219 # initialize the script plug-in
220 def initializePlugin(mobject):
221  mplugin = OpenMayaMPx.MFnPlugin(mobject)
222 
223  try:
224  mplugin.registerTransform( kRockingTransformPluginName, kRockingTransformNodeID, \
225  nodeCreator, nodeInitializer, matrixCreator, kRockingTransformMatrixID )
226  except:
227  sys.stderr.write( "Failed to register transform: %s\n" % kRockingTransformPluginName )
228  raise
229 
230 # uninitialize the script plug-in
231 def uninitializePlugin(mobject):
232  mplugin = OpenMayaMPx.MFnPlugin(mobject)
233 
234  try:
235  mplugin.deregisterNode( kRockingTransformNodeID )
236  except:
237  sys.stderr.write( "Failed to unregister node: %s\n" % kRockingTransformPluginName )
238  raise
239 
240 # =====================================================================
241 # Copyright 2017 Autodesk, Inc. All rights reserved.
242 #
243 # This computer source code and related instructions and comments are
244 # the unpublished confidential and proprietary information of Autodesk,
245 # Inc. and are protected under applicable copyright and trade secret
246 # law. They may not be disclosed to, copied or used by any third party
247 # without the prior written consent of Autodesk, Inc.
248 # =====================================================================