Skip to content

Commit ee14e24

Browse files
committed
support for attribute driven pivots
1 parent b46a3b3 commit ee14e24

File tree

1 file changed

+134
-19
lines changed

1 file changed

+134
-19
lines changed

ml_pivot.py

Lines changed: 134 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# / __ `__ \/ / Licensed under Creative Commons BY-SA
66
# / / / / / / / http://creativecommons.org/licenses/by-sa/3.0/
77
# /_/ /_/ /_/_/ _________
8-
# /_________/ Revision 2, 2017-06-26
8+
# /_________/ Revision 3, 2017-07-17
99
# _______________________________
1010
# - -/__ Installing Python Scripts __/- - - - - - - - - - - - - - - - - - - -
1111
#
@@ -45,7 +45,7 @@
4545
__author__ = 'Morgan Loomis'
4646
__license__ = 'Creative Commons Attribution-ShareAlike'
4747
__category__ = 'animationScripts'
48-
__revision__ = 2
48+
__revision__ = 3
4949

5050
try:
5151
from PySide2 import QtGui, QtCore
@@ -60,7 +60,7 @@
6060

6161
try:
6262
import ml_utilities as utl
63-
utl.upToDateCheck(30)
63+
utl.upToDateCheck(31)
6464
except ImportError:
6565
result = mc.confirmDialog( title='Module Not Found',
6666
message='This tool requires the ml_utilities module. Once downloaded you will need to restart Maya.',
@@ -123,8 +123,7 @@ def __init__(self):
123123
self.scriptJob = None
124124
self.keypressFilter = PivotKeypressFilter(self.bakePivot, self.cleanup)
125125

126-
127-
126+
128127
def editPivot(self, *args):
129128
sel = mc.ls(sl=True)
130129

@@ -140,14 +139,85 @@ def editPivot(self, *args):
140139
#we have a pivot handle selected
141140
return
142141

142+
self.node = sel[0]
143+
143144
if is_pivot_connected(sel[0]):
145+
driverAttr = pivot_driver_attr(sel[0])
146+
if driverAttr:
147+
self.editPivotDriver(driverAttr)
148+
else:
149+
om.MGlobal.displayWarning('Pivot attribute is connected, unable to edit.')
144150
return
145151

146-
self.node = sel[0]
152+
self.editPivotHandle()
153+
154+
155+
def editPivotDriver(self, driver):
147156

148-
qt_maya_window.installEventFilter(self.keypressFilter)
157+
self.pivotDriver = driver
158+
159+
#get driver range
160+
node,attr = driver.split('.',1)
161+
value = mc.getAttr(driver)
162+
163+
minValue = mc.attributeQuery(attr, node=node, minimum=True)[0]
164+
maxValue = mc.attributeQuery(attr, node=node, maximum=True)[0]
165+
166+
#create a ui with a slider
167+
self.pivotDriverWindow = 'ml_pivot_editPivotDriverUI'
168+
169+
if mc.window(self.pivotDriverWindow, exists=True):
170+
mc.deleteUI(self.pivotDriverWindow)
171+
window = mc.window(self.pivotDriverWindow, width=1, height=1)
172+
mc.columnLayout()
173+
self.floatSlider = mc.floatSliderButtonGrp(label=attr,
174+
field=True,
175+
value=value,
176+
buttonLabel='Bake',
177+
minValue=minValue,
178+
maxValue=maxValue,
179+
buttonCommand=self.doEditPivotDriver )
180+
mc.showWindow( window )
181+
mc.window(self.pivotDriverWindow, edit=True, width=1, height=1)
182+
183+
def doEditPivotDriver(self, *args):
184+
185+
newValue = mc.floatSliderButtonGrp(self.floatSlider, query=True, value=True)
186+
try:
187+
mc.deleteUI(self.pivotDriverWindow)
188+
except:
189+
pass
190+
191+
currentValue = mc.getAttr(self.pivotDriver)
192+
if newValue == currentValue:
193+
return
194+
195+
oldRP = mc.getAttr(self.node+'.rotatePivot')[0]
196+
mc.setAttr(self.pivotDriver, newValue)
197+
newRP = mc.getAttr(self.node+'.rotatePivot')[0]
198+
mc.setAttr(self.pivotDriver, currentValue)
199+
200+
parentPosition = mc.group(em=True)
201+
offsetPosition = mc.group(em=True)
202+
offsetPosition = mc.parent(offsetPosition, parentPosition)[0]
203+
mc.setAttr(offsetPosition+'.translate', newRP[0]-oldRP[0], newRP[1]-oldRP[1], newRP[2]-oldRP[2])
204+
205+
mc.delete(mc.parentConstraint(self.node, parentPosition))
206+
207+
utl.matchBake(source=[self.node], destination=[parentPosition], bakeOnOnes=True, maintainOffset=False, preserveTangentWeight=False)
208+
209+
mc.cutKey(self.pivotDriver)
210+
mc.setAttr(self.pivotDriver, newValue)
211+
mc.refresh()
212+
utl.matchBake(source=[offsetPosition], destination=[self.node], bakeOnOnes=True, maintainOffset=False, preserveTangentWeight=False, rotate=False)
213+
214+
mc.delete(parentPosition)
149215

150216

217+
def editPivotHandle(self):
218+
219+
qt_maya_window.installEventFilter(self.keypressFilter)
220+
151221
#create transform
152222
self.pivotHandle = mc.group(em=True, name='Adjust_Pivot')
153223
mc.setAttr(self.pivotHandle+'.rotate', lock=True)
@@ -236,11 +306,29 @@ def cleanup(self):
236306
mc.lockNode(each, lock=False)
237307
mc.delete(each)
238308

309+
def pivot_driver_attr(node):
310+
'''
311+
Start with supporting pivots driven by remap value nodes, more support in the future as requested.
312+
'''
313+
#rpSrc = mc.listConnections(node+'.rotatePivot', source=True, destination=False, plugs=True)
314+
#if rpSrc and rpSrc[0].endswith('.translate') and mc.getAttr(rpSrc[0], keyable=True):
315+
#return rpSrc[0]
316+
317+
for each in ('rotatePivotX', 'rotatePivotY', 'rotatePivotZ'):
318+
src = mc.listConnections(node+'.'+each, source=True, destination=False)
319+
if not src:
320+
continue
321+
srcType = mc.nodeType(src[0])
322+
if srcType == 'remapValue':
323+
src = mc.listConnections(src[0]+'.inputValue', source=True, destination=False, plugs=True)
324+
if src and mc.getAttr(src[0], keyable=True) and not mc.getAttr(src[0], lock=True):
325+
return src[0]
326+
return None
327+
239328

240329
def is_pivot_connected(node):
241330
for each in ('rotatePivot', 'rotatePivotX', 'rotatePivotY', 'rotatePivotZ'):
242331
if mc.listConnections(node+'.'+each, source=True, destination=False):
243-
om.MGlobal.displayWarning('Pivot attribute is connected, unable to edit.')
244332
return True
245333
return False
246334

@@ -256,24 +344,49 @@ def reset_pivot(*args):
256344
om.MGlobal.displayWarning('Only works on one node at a time.')
257345
return
258346

259-
if is_pivot_connected(sel[0]):
260-
return
261-
262347
node = sel[0]
263-
264-
pivotPosition = mc.getAttr(node+'.rotatePivot')[0]
265-
if pivotPosition == (0.0,0.0,0.0):
266-
return
267-
348+
driver = None
349+
driver_value = None
350+
driver_default = None
351+
352+
if is_pivot_connected(node):
353+
driver = pivot_driver_attr(node)
354+
if driver:
355+
dNode,dAttr = driver.split('.',1)
356+
driver_value = mc.getAttr(driver)
357+
driver_default = mc.attributeQuery(dAttr, node=dNode, listDefault=True)[0]
358+
if driver_default == driver_value:
359+
return
360+
else:
361+
om.MGlobal.displayWarning('Pivot attribute is connected, unable to edit.')
362+
return
363+
364+
if not driver:
365+
pivotPosition = mc.getAttr(node+'.rotatePivot')[0]
366+
if pivotPosition == (0.0,0.0,0.0):
367+
return
368+
268369
tempPosition = mc.group(em=True)
269370
tempPivot = mc.group(em=True)
270371
tempPivot = mc.parent(tempPivot, node)[0]
271-
mc.setAttr(tempPivot+'.translate', 0,0,0)
372+
if driver:
373+
mc.setAttr(driver, driver_default)
374+
newRP = mc.getAttr(node+'.rotatePivot')[0]
375+
mc.setAttr(driver, driver_value)
376+
mc.setAttr(tempPivot+'.translate', *newRP)
377+
else:
378+
mc.setAttr(tempPivot+'.translate', 0,0,0)
379+
272380
mc.setAttr(tempPivot+'.rotate', 0,0,0)
273381

274382
utl.matchBake(source=[tempPivot], destination=[tempPosition], bakeOnOnes=True, maintainOffset=False, preserveTangentWeight=False, rotate=False)
275-
276-
mc.setAttr(node+'.rotatePivot', 0,0,0)
383+
384+
if driver:
385+
mc.setAttr(driver, driver_default)
386+
else:
387+
mc.setAttr(node+'.rotatePivot', 0,0,0)
388+
389+
mc.refresh()
277390
utl.matchBake(source=[tempPosition], destination=[node], bakeOnOnes=True, maintainOffset=False, preserveTangentWeight=False, rotate=False)
278391

279392
mc.delete(tempPosition,tempPivot)
@@ -290,3 +403,5 @@ def reset_pivot(*args):
290403
# Revision 1: 2016-06-21 : First publish.
291404
#
292405
# Revision 2: 2017-06-26 : update for pySide2, maya 2017
406+
#
407+
# Revision 3: 2017-07-17 : initial support for attribute driven pivots

0 commit comments

Comments
 (0)