scripted/rockingTransform.py

scripted/rockingTransform.py
1 #-
2 # ==========================================================================
3 # Copyright (C) 1995 - 2006 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 # This plug-in implements an example custom transform that
40 # can be used to perform a rocking motion around the X axix.
41 # Geometry of any rotation can be made a child of this transform
42 # to demonstrate the effect.
43 # The plug-in contains two pieces:
44 # 1. The custom transform node -- rockingTransformNode
45 # 2. The custom transformation matrix -- rockingTransformMatrix
46 # These classes are used together in order to implement the
47 # rocking motion. Note that the rock attribute is stored outside
48 # of the regular transform attributes.
49 
50 # Usage:
51 # import maya.cmds
52 # maya.cmds.loadPlugin("rockingTransform.py")
53 # maya.cmds.file(f=True,new=True)
54 # maya.cmds.polyPlane()
55 # maya.cmds.select("pPlane1",r=True)
56 # maya.cmds.rotate(-15,-15,-15,r=True,ws=True)
57 # maya.cmds.createNode("spRockingTransform")
58 # maya.cmds.parent("pPlane1","spRockingTransform1")
59 # maya.cmds.setAttr("spRockingTransform1.rockx",55)
60 #
61 
62 import maya.OpenMaya as OpenMaya
63 import maya.OpenMayaMPx as OpenMayaMPx
64 import math
65 import sys
66 
67 kRockingTransformPluginName = "spRockingTransform"
68 kRockingTransformNodeName = "spRockingTransformNode"
69 kRockingTransformNodeID = OpenMaya.MTypeId(0x87014)
70 kRockingTransformMatrixID = OpenMaya.MTypeId(0x87015)
71 
72 # keep track of instances of rockingTransformMatrix to get around script limitation
73 # with proxy classes of base pointers that actually point to derived
74 # classes
75 kTrackingDictionary = {}
76 
77 
78 class rockingTransformMatrix(OpenMayaMPx.MPxTransformationMatrix):
79 
80  def __init__(self):
81  OpenMayaMPx.MPxTransformationMatrix.__init__(self)
82  kTrackingDictionary[OpenMayaMPx.asHashable(self)] = self
83  self.rockXValue = 0.0
84 
85  def __del__(self):
86  del kTrackingDictionary[OpenMayaMPx.asHashable(self)]
87 
88  def setRockInX(self,rockingValue):
89  self.rockXValue = rockingValue
90 
91  def getRockInX(self):
92  return self.rockXValue
93 
94  def asMatrix(self,percent=None):
95  """
96  Find the new matrix and return it
97  """
98  if percent == None:
99  matrix = OpenMayaMPx.MPxTransformationMatrix.asMatrix(self)
100  tm = OpenMaya.MTransformationMatrix(matrix)
101  quat = self.rotation()
102  rockingValue = self.getRockInX()
103  newTheta = math.radians( rockingValue )
104  quat.setToXAxis( newTheta )
105  tm.addRotationQuaternion( quat.x, quat.y, quat.z, quat.w, OpenMaya.MSpace.kTransform )
106  return tm.asMatrix()
107  else:
108  m = OpenMayaMPx.MPxTransformationMatrix(self)
109  #
110  trans = m.translation()
111  rotatePivotTrans = m.rotatePivot()
112  scalePivotTrans = m.scalePivotTranslation()
113  trans = trans * percent
114  rotatePivotTrans = rotatePivotTrans * percent
115  scalePivotTrans = scalePivotTrans * percent
116  m.translateTo(trans)
117  m.setRotatePivot( rotatePivotTrans )
118  m.setScalePivotTranslation( scalePivotTrans )
119  #
120  quat = self.rotation()
121  rockingValue = self.getRockInX()
122  newTheta = math.radians( rockingValue )
123 
124  quat.setToXAxis( newTheta )
125  m.rotateBy( quat )
126  eulerRotate = m.eulerRotation()
127  m.rotateTo( eulerRotate * percent, OpenMaya.MSpace.kTransform )
128  #
129  s = self.scale( OpenMaya.MSpace.kTransform )
130  s.x = 1.0 + ( s.x - 1.0 ) * percent
131  s.y = 1.0 + ( s.y - 1.0 ) * percent
132  s.z = 1.0 + ( s.z - 1.0 ) * percent
133  m.scaleTo( s, OpenMaya.MSpace.kTransform )
134  #
135  return m.asMatrix()
136 
137 
138 class rockingTransformNode(OpenMayaMPx.MPxTransform):
139  aRockInX = OpenMaya.MObject()
140 
141  def __init__(self, transform=None):
142  if transform is None:
143  OpenMayaMPx.MPxTransform.__init__(self)
144  else:
145  OpenMayaMPx.MPxTransform.__init__(self, transform)
146  self.rockXValue = 0.0
147 
148  def createTransformationMatrix(self):
149  return OpenMayaMPx.asMPxPtr( rockingTransformMatrix() )
150 
151  def className(self):
152  return kRockingTransformNodeName
153 
154  #
155  def validateAndSetValue(self, plug, handle, context):
156  if not plug.isNull():
157  block = self._forceCache(context)
158  blockHandle = block.outputValue(plug)
159 
160  if plug == self.aRockInX:
161  # Update our new rock in x value
162  rockInX = handle.asDouble()
163  blockHandle.setDouble(rockInX)
164 
165  # Update the custom transformation matrix to the
166  # right value.
167  ltm = self.getRockingTransformationMatrix()
168  if ltm is not None:
169  ltm.setRockInX(rockInX)
170 
171  blockHandle.setClean()
172 
173  # Mark the matrix as dirty so that DG information
174  # will update.
175  self._dirtyMatrix()
176 
177  OpenMayaMPx.MPxTransform.validateAndSetValue(self, plug, handle, context)
178 
179 
180  def getRockingTransformationMatrix(self):
181  baseXform = self.transformationMatrixPtr()
182  return kTrackingDictionary[OpenMayaMPx.asHashable(baseXform)]
183 
184 
185 # create/initialize node and matrix
186 def matrixCreator():
187  return OpenMayaMPx.asMPxPtr( rockingTransformMatrix() )
188 
189 def nodeCreator():
190  return OpenMayaMPx.asMPxPtr( rockingTransformNode() )
191 
192 def nodeInitializer():
193  numFn = OpenMaya.MFnNumericAttribute()
194 
195  rockingTransformNode.aRockInX = numFn.create("RockInX", "rockx", OpenMaya.MFnNumericData.kDouble, 0.0)
196 
197  numFn.setKeyable(True)
198  numFn.setAffectsWorldSpace(True)
199 
200  rockingTransformNode.addAttribute(rockingTransformNode.aRockInX)
201  rockingTransformNode.mustCallValidateAndSet(rockingTransformNode.aRockInX)
202  return
203 
204 # initialize the script plug-in
205 def initializePlugin(mobject):
206  mplugin = OpenMayaMPx.MFnPlugin(mobject)
207 
208  try:
209  mplugin.registerTransform( kRockingTransformPluginName, kRockingTransformNodeID, \
210  nodeCreator, nodeInitializer, matrixCreator, kRockingTransformMatrixID )
211  except:
212  sys.stderr.write( "Failed to register transform: %s\n" % kRockingTransformPluginName )
213  raise
214 
215 # uninitialize the script plug-in
216 def uninitializePlugin(mobject):
217  mplugin = OpenMayaMPx.MFnPlugin(mobject)
218 
219  try:
220  mplugin.deregisterNode( kRockingTransformNodeID )
221  except:
222  sys.stderr.write( "Failed to unregister node: %s\n" % kRockingTransformPluginName )
223  raise