Wednesday, September 10, 2014

Marker Keys UI



The Marker Keys tool looks up on what frames in the timeline (or a selected time range) the original object has keyframes and sets "marker" keyframes (just for reference) on the recipient object.

USES
Sometimes after my blocking animation pass is done, a new ctrl is added to the rig (e.g. clothes ctrls, accessory ctrl) or a new prop is added to the scene. The new ctrl doesn't have any keys on the timeline, so I use marker keys as a reference to know where my blocking poses are, and that way my new ctrl will have keyframes on the same times as the rest of my ctrls. I also use marker keys when part of my blocking is not working (like an arm for example) and I want to delete all keyframes on those ctrls and start from scratch.

INTERFACE
Selection section
This section is used to determine the objects and time range that will be used by the "SET MARKER KEYS" function. First you need to select an original object (the one that already has keyframes) and press "assign original" and then select the recipient object (the one that will get the marker keys) and press "assign recipient". If you select multiple objects, only the first one will be assigned.
Then you can select a time range, or by default the UI will load  the values you have your timeline set to.

Keyable channels section
You can select which attributes get keyed. By default, only Tx is selected, since you only need to have one channel keyed to get a red "tick" on your timeline and be able to use the "," and "." buttons to navigate between keyframes. Selecting no channels at all will result in all attributes being keyed, including scale, visibility and any other attributes your object may have.

Finally, press "SET MARKER KEYS" and the keyframes will be assigned to your recipient.

Additional tools section
The lower section consists of additional tools that can be useful when working with this method. These tools work on the current selection, no matter what's assigned as Original or Recipient at the top.

Copy to next key:
Copies the key at the current time and pastes it where the next marker key is.
Once the marker keys are set, I'll go to each one and position the ctrl where I want it at that point in time. When I go to the next marker key, the ctrl will go back to the initial position (where it was when I set the marker keys), in most cases, this is not what I want, I want to keep animating from the position in the previous pose. For that purpose, before moving to the next marker key, I use the "copy to next key" tool.

Delete all keys:
Deletes all keyframes in the time range determined in the Selection section.

Set keyframes per channel:
Sets a keyframe only on the channel clicked. This is the same as right clicking on a channel in the channel box and selecting "Key Selected", but you only need to click one button.


INSTALLATION
To get the Marker keys UI, download the script file and save it in your maya/version/scripts folder:
Download markerKeys.py

Then run the following code in the script editor (make sure to be in a python tab):

import markerKeys
reload(markerKeys)

You can save these lines in a shelf button for easy access.

If you don't want to download the file you can just copy the code below to the script editor and drag it onto your custom shelves so you can access it at any time (remember to save your shelves before quitting Maya)
import maya.cmds as mc
from functools import partial
#check if markerKeysUI is already open
if mc.window('markerKeysUI', query=True, exists=True):
mc.deleteUI('markerKeysUI', window=True)
original = None
recipient = None
def assignOrig(arg=None):
global original
original = mc.ls(sl=True)
if original:
mc.text(origSelected, e=True, l=str(original[0]))
def assignRecipient(arg=None):
global recipient
recipient = mc.ls(sl=True)
if recipient:
mc.text(recipientSelected, e=True, l=str(recipient[0]))
def warningMsg(msg,arg=None):
mc.confirmDialog(title='Warning', message=msg, button='ok')
def setKeys(arg=None):
#query time range input values
startTime = mc.intFieldGrp(timeRange, query=True, value1=True)
endTime = mc.intFieldGrp(timeRange, query=True, value2=True)
#check original not empty list or None
if not original:
warningMsg('Please assign original')
return
#check recipient not empty list or None
elif not recipient:
warningMsg('Please assign recipient')
return
else:
#find keyframes for original object
keyframes = mc.keyframe(original, time=(startTime, endTime), query=True)
#check if there are keyframes in time range
if not keyframes:
warningMsg('No keys in this time range')
return
else:
#convert to set to remove duplicates
keyframeSet = set(keyframes)
#find selected channels to key
selChannels =()
if mc.checkBoxGrp(tChannels, query=True, value1=True):
selChannels = selChannels+('tx',)
if mc.checkBoxGrp(tChannels, query=True, value2=True):
selChannels = selChannels+('ty',)
if mc.checkBoxGrp(tChannels, query=True, value3=True):
selChannels = selChannels+('tz',)
if mc.checkBoxGrp(rChannels, query=True, value1=True):
selChannels = selChannels+('rx',)
if mc.checkBoxGrp(rChannels, query=True, value2=True):
selChannels = selChannels+('ry',)
if mc.checkBoxGrp(rChannels, query=True, value3=True):
selChannels = selChannels+('rz',)
#set keyframes on recipient
for time in keyframeSet:
mc.setKeyframe(recipient, time=time, at=selChannels)
#copy values to next keyframe
def copyToNext(arg=None):
selected = mc.ls(sl=True)
#check if object selected
if not selected:
warningMsg('Please select object')
return
else:
time = mc.currentTime(query=True)
nextKey = mc.findKeyframe(timeSlider=True, which='next')
#check there are more keys
if nextKey == time:
warningMsg('This is the only key')
return
curvesCopied = mc.copyKey(selected, time=(time, time))
#check if anything was copied to clipboard
if curvesCopied == 0:
warningMsg('Nothing to paste')
return
else:
mc.pasteKey(selected, time=(nextKey, nextKey))
#delete all keyframes in time range
def delAllKeys(arg=None):
selected = mc.ls(sl=True)
#check if object selected
if not selected:
warningMsg('Please select object')
return
startTime = mc.intFieldGrp(timeRange, query=True, value1=True)
endTime = mc.intFieldGrp(timeRange, query=True, value2=True)
mc.cutKey(selected, time=(startTime, endTime))
def keyChannel(attribute, arg=None):
selected = mc.ls(sl=True)
#check if object selected
if not selected:
warningMsg('Please select object')
return
mc.setKeyframe(at=attribute)
######## GUI
mc.window('markerKeysUI', title='Marker keys')
mc.columnLayout( adjustableColumn=True )
##Selection
mc.frameLayout( label='Selection', borderStyle='in' )
mc.rowColumnLayout(numberOfColumns=3, columnWidth=[(1, 60), (2, 180), (3, 100)])
#original
mc.text(label='Original:', align='left')
origSelected = mc.text('select original', font='obliqueLabelFont', align='left')
mc. button(label='assign', command=partial(assignOrig))
#recipient
mc.text(label='Recipient:', align='left')
recipientSelected = mc.text(label='select recipient', font='obliqueLabelFont', align='left')
mc. button(label='assign', command=partial(assignRecipient))
mc.text(label='Time range:', align='left')
#get timeline values
minTime = mc.playbackOptions(query=True, minTime=True)
maxTime = mc.playbackOptions(query=True, maxTime=True)
#Time range
timeRange = mc.intFieldGrp(numberOfFields=2, value1=minTime, value2=maxTime)
mc.setParent( '..' )
mc.setParent( '..' )
##Keyable channels
mc.frameLayout( label='Keyable channels', borderStyle='out' )
tChannels = mc.checkBoxGrp( numberOfCheckBoxes=3, labelArray3=['Tx', 'Ty', 'Tz'], value1=True )
rChannels = mc.checkBoxGrp( numberOfCheckBoxes=3, labelArray3=['Rx', 'Ry', 'Rz'] )
#set keys button
mc. button(label='SET MARKER KEYS', command=partial(setKeys))
mc.setParent( '..' )
mc.setParent( '..' )
##Additional tools
mc.frameLayout( label='Additional tools', borderStyle='etchedOut' )
mc. button(label='copy values to next key', command=partial(copyToNext))
mc. button(label='delete all keys', command=partial(delAllKeys))
mc.text(label='Set keyframes per channel:', align='left')
mc.gridLayout(numberOfColumns=6)
mc. button(label='Tx', command=partial(keyChannel,('tx')))
mc. button(label='Ty', command=partial(keyChannel,('ty')))
mc. button(label='Tz', command=partial(keyChannel,('tz')))
mc. button(label='Rx', command=partial(keyChannel,('rx')))
mc. button(label='Ry', command=partial(keyChannel,('ry')))
mc. button(label='Rz', command=partial(keyChannel,('rz')))
mc.setParent( '..' )
mc.setParent( '..' )
mc.showWindow('markerKeysUI')
view raw MarkerKeys hosted with ❤ by GitHub