5
5
# / __ `__ \/ / Licensed under Creative Commons BY-SA
6
6
# / / / / / / / http://creativecommons.org/licenses/by-sa/3.0/
7
7
# /_/ /_/ /_/_/ _________
8
- # /_________/ Revision 4, 2014-03-01
8
+ # /_________/ Revision 5, 2017-07-19
9
9
# _______________________________
10
10
# - -/__ Installing Python Scripts __/- - - - - - - - - - - - - - - - - - - -
11
11
#
46
46
__author__ = 'Morgan Loomis'
47
47
__license__ = 'Creative Commons Attribution-ShareAlike'
48
48
__category__ = 'animationScripts'
49
- __revision__ = 4
49
+ __revision__ = 5
50
50
51
51
import maya .cmds as mc
52
52
import maya .mel as mm
53
53
from maya import OpenMaya
54
54
55
55
try :
56
56
import ml_utilities as utl
57
- utl .upToDateCheck (9 )
57
+ utl .upToDateCheck (31 )
58
58
except ImportError :
59
59
result = mc .confirmDialog ( title = 'Module Not Found' ,
60
60
message = 'This tool requires the ml_utilities module. Once downloaded you will need to restart Maya.' ,
@@ -80,6 +80,9 @@ def ui():
80
80
81
81
82
82
def _getStartAndEnd ():
83
+ '''
84
+ Only return start and end if frame range is highlighted. Otherwise use all available animation.
85
+ '''
83
86
84
87
gPlayBackSlider = mm .eval ('$temp=$gPlayBackSlider' )
85
88
if mc .timeControl (gPlayBackSlider , query = True , rangeVisible = True ):
@@ -88,16 +91,15 @@ def _getStartAndEnd():
88
91
return None , None
89
92
90
93
91
- def copySingle (source = None , destination = None , pasteMethod = 'replace' , offset = 0 , addToLayer = False ):
94
+ def copySingle (source = None , destination = None , pasteMethod = 'replace' , offset = 0 , addToLayer = False , rotateOrder = True ):
92
95
'''
93
96
Copy animation from a source node and paste it to a destination node
94
97
'''
95
98
96
99
start , end = _getStartAndEnd ()
97
-
100
+
98
101
if not source and not destination :
99
102
sel = mc .ls (sl = True )
100
-
101
103
if len (sel ) != 2 :
102
104
OpenMaya .MGlobal .displayWarning ('Please select exactly 2 objects.' )
103
105
return
@@ -108,14 +110,14 @@ def copySingle(source=None, destination=None, pasteMethod='replace', offset=0, a
108
110
layer = None
109
111
if addToLayer :
110
112
layer = utl .createAnimLayer (destination , namePrefix = 'ml_cp' )
111
-
112
- copyAnimation (source = source , destination = destination , pasteMethod = pasteMethod , offset = offset , start = start , end = end , layer = layer )
113
113
114
- # if sel:
115
- # mc.select(sel)
114
+ copyAnimation (source = source , destination = destination , pasteMethod = pasteMethod , offset = offset , start = start , end = end , layer = layer , rotateOrder = rotateOrder )
115
+
116
+ #if sel:
117
+ #mc.select(sel)
116
118
117
119
118
- def copyHierarchy (sourceTop = None , destinationTop = None , pasteMethod = 'replace' , offset = 0 , addToLayer = False , layerName = None ):
120
+ def copyHierarchy (sourceTop = None , destinationTop = None , pasteMethod = 'replace' , offset = 0 , addToLayer = False , layerName = None , rotateOrder = True ):
119
121
'''
120
122
Copy animation from a source hierarchy and paste it to a destination hierarchy.
121
123
'''
@@ -127,16 +129,14 @@ def copyHierarchy(sourceTop=None, destinationTop=None, pasteMethod='replace', of
127
129
if len (sel ) != 2 :
128
130
OpenMaya .MGlobal .displayWarning ('Please select exactly 2 objects.' )
129
131
return
130
-
132
+
131
133
sourceTop = sel [0 ]
132
134
destinationTop = sel [1 ]
133
135
134
136
#get keyed objects below source
135
- nodes = mc .listRelatives (sourceTop , pa = True , ad = True )
136
- if not nodes :
137
- nodes = list ()
137
+ nodes = mc .listRelatives (sourceTop , pa = True , ad = True ) or []
138
138
nodes .append (sourceTop )
139
- keyed = list ()
139
+ keyed = []
140
140
141
141
for node in nodes :
142
142
# this will only return time based keyframes, not driven keys
@@ -147,42 +147,45 @@ def copyHierarchy(sourceTop=None, destinationTop=None, pasteMethod='replace', of
147
147
return
148
148
149
149
#get a list of all nodes under the destination
150
- destNodes = mc .listRelatives (destinationTop , ad = True )
151
- if not destNodes :
152
- destNodes = list ()
153
- destNodes .append (destinationTop )
150
+ allDestNodes = mc .listRelatives (destinationTop , ad = True , pa = True ) or []
151
+ allDestNodes .append (destinationTop )
152
+
153
+ destNodeMap = {}
154
+ duplicate = []
155
+ for each in allDestNodes :
156
+ name = each .rsplit ('|' )[- 1 ].rsplit (':' )[- 1 ]
157
+ if name in duplicate :
158
+ continue
159
+ if name in destNodeMap .keys ():
160
+ duplicate .append (name )
161
+ continue
162
+ destNodeMap [name ] = each
154
163
155
- destNS = utl .getNamespace (destinationTop )
156
- destNames = [x .rpartition (':' )[- 1 ] for x in destNodes ]
164
+ destNS = utl .getNamespace (destinationTop )
157
165
158
166
layer = None
159
167
if addToLayer :
160
168
if not layerName :
161
169
layerName = 'copyHierarchy'
162
170
layer = utl .createAnimLayer (name = layerName )
163
-
171
+
164
172
for node in keyed :
165
- nodeName = mc .ls (node , shortNames = True )[0 ]
166
-
167
- #strip namespace
168
- if ':' in nodeName :
169
- nodeName = nodeName .rpartition (':' )[- 1 ]
173
+ #strip name
174
+ nodeName = node .rsplit ('|' )[- 1 ].rsplit (':' )[- 1 ]
170
175
171
- if nodeName in destNames :
172
- destNode = mc .ls (destNS + nodeName )
173
- if not destNode :
174
- print 'Cannot find destination node: ' + destNS + ':' + nodeName
175
- continue
176
- if len (destNode ) > 1 :
177
- print 'Two or more destination nodes have the same name: ' + destNS + ':' + nodeName
178
- continue
176
+ if nodeName in duplicate :
177
+ print 'Two or more destination nodes have the same name: ' + destNS + nodeName
178
+ continue
179
+ if nodeName not in destNodeMap .keys ():
180
+ print 'Cannot find destination node: ' + destNS + nodeName
181
+ continue
179
182
180
- copyAnimation (source = node , destination = destNode [ 0 ], pasteMethod = pasteMethod , offset = offset , start = start , end = end , layer = layer )
183
+ copyAnimation (source = node , destination = destNodeMap [ nodeName ], pasteMethod = pasteMethod , offset = offset , start = start , end = end , layer = layer , rotateOrder = rotateOrder )
181
184
182
185
# if sel:
183
186
# mc.select(sel)
184
187
185
- def copyAnimation (source = None , destination = None , pasteMethod = 'replace' , offset = 0 , start = None , end = None , layer = None ):
188
+ def copyAnimation (source = None , destination = None , pasteMethod = 'replace' , offset = 0 , start = None , end = None , layer = None , rotateOrder = True ):
186
189
'''
187
190
Actually do the copy and paste from one node to another. If start and end frame is specified,
188
191
set a temporary key before copying, and delete it afterward.
@@ -196,6 +199,12 @@ def copyAnimation(source=None, destination=None, pasteMethod='replace', offset=0
196
199
utl .minimizeRotationCurves (source )
197
200
utl .minimizeRotationCurves (destination )
198
201
202
+ if rotateOrder :
203
+ try :
204
+ if mc .getAttr (destination + '.rotateOrder' , keyable = True ):
205
+ mc .setAttr (destination + '.rotateOrder' , mc .getAttr (source + '.rotateOrder' ))
206
+ except :pass
207
+
199
208
if pasteMethod == 'replaceCompletely' or not start or not end :
200
209
mc .copyKey (source )
201
210
if layer :
@@ -209,8 +218,8 @@ def copyAnimation(source=None, destination=None, pasteMethod='replace', offset=0
209
218
return
210
219
211
220
#story cut keytimes as 2 separate lists means we only have to run 2 cutkey commands, rather than looping through each
212
- cutStart = list ()
213
- cutEnd = list ()
221
+ cutStart = []
222
+ cutEnd = []
214
223
for curve in animCurves :
215
224
216
225
#does it have keyframes on the start and end frames?
@@ -225,7 +234,7 @@ def copyAnimation(source=None, destination=None, pasteMethod='replace', offset=0
225
234
if not endKey :
226
235
mc .setKeyframe (curve , time = (end ,), insert = True )
227
236
cutEnd .append (curve )
228
-
237
+
229
238
mc .copyKey (source , time = (start ,end ))
230
239
if layer :
231
240
for each in mc .ls (type = 'animLayer' ):
@@ -253,3 +262,5 @@ def copyAnimation(source=None, destination=None, pasteMethod='replace', offset=0
253
262
# Revision 3: 2012-11-28 : remove debug print
254
263
#
255
264
# Revision 4: 2014-03-01 : Adding category and fixing bad argument name.
265
+ #
266
+ # Revision 5: 2017-07-19 : support for non-namespaced hierarchies, transferring rotateOrder
0 commit comments