Red9_AnimationUtils

Red9_AnimationUtils deals with all the key, attribute and time management within Red9. Anything from copying keys between processed hierarchies to Mirroring animation data.

Code examples:

ProcessNodes

All of the functions which have the ProcessNodes call share the same underlying functionality as described below. This is designed to process the given input nodes in a consistent manor across all the functions. Params: ‘nodes’ and ‘filterSettings’ are treated as special and build up a MatchedNode object that contains a tuple of matching pairs based on the given settings.

AnimFunctions example:

The main AnimFunctions class is designed to run with an r9Core.FilterNode object that is responsible for how we process hierarchies. If one isn’t passed as an arg then the code simply processes the ‘nodes’ args in zipped pairs. See the documentation on the r9Core.MatchedNodeInputs for more detail.

All the AnimFunctions such as copyKeys, copyAttrs etc use the same base setup

>>> import Red9_CoreUtils as r9Core
>>> import maya.cmds as cmds
>>> 
>>> #===========================
>>> # When Processing hierarchies:
>>> #===========================
>>> # The Filter_Settings object required for hierarchy processing is now bound to 
>>> # the class directly so you no longer need to create a filterSettigns object directly!
>>> # Lets set the filter to process nodes with a given attr 'myControl' who's type is 'nurbscurve'
>>> animFunc=r9Anim.AnimFunctions()
>>> animFunc.settings = r9Core.FilterNode_Settings()
>>> animFunc.settings.nodeTypes ='nurbsCurve'
>>> animFunc.settings.searchAttrs = 'myControl'
>>> animFunc.settings.printSettings()
>>> 
>>> # now run any of the AnimFunctions and pass in nodes which with the filter active
>>> # as above would be the 2 root nodes of the hierarchies to filter
>>> 
>>> animFunc.copyAttributes(cmds.ls(sl=True,l=True))
>>> 
>>> animFunc.snapTransform(nodes=cmds.ls(sl=True), time=r9Anim.timeLineRangeGet())
>>> 
>>> #==============================
>>> # When processing simple objects:
>>> #==============================
>>> # If you simply ignore the filterSettings you can just process given nodes directly
>>> # the nodes are zipped into selected pairs obj[0]>obj[1], obj[2]>obj[3] etc
>>> anim = r9Anim.AnimFunctions()
>>> anim.snapTransform(nodes=cmds.ls(sl=True), time=r9Anim.timeLineRangeGet())

Core Functions

getChannelBoxSelection() return a list of attributes selected in the ChannelBox
getChannelBoxAttrs([node, asDict, incLocked]) return the status of all attrs on the given node, either as a flat list or
getSettableChannels([node, incStatics]) return a list of settable attributes on a given node.
getAnimLayersFromGivenNodes(nodes) return all animLayers associated with the given nodes
timeLineRangeGet([always]) Return the current PlaybackTimeline OR if a range is selected in the TimeLine, (Highlighted in Red) return that instead.
timeLineRangeProcess(start, end, step[, incEnds]) Simple wrapper function to take a given framerange and return a list[] containing the actual keys required for processing.
mergeAnimLayers(nodes[, deleteBaked]) from the given nodes find, merge and remove any animLayers found
eulerSelected() cheap trick! for selected objects run a Euler Filter and then delete Static curves

Core Classes

AnimationUI([dockUI])
AnimFunctions([filterSettings]) Most of the main Animation Functions take a settings object which is responsible for hierarchy processing.
RandomizeKeys() This is a simple implementation of a Key Randomizer, designed to add noise to animations.
FilterCurves()
MirrorHierarchy([nodes, filterSettings]) This class is designed to mirror pose and animation data on any given hierarchy.
MirrorSetup()
AnimationLayerContext(srcNodes[, ...]) Context Manager for merging animLayers down and restoring
CameraTracker([fixed])
RED_ANIMATION_UI_OPENCALLBACKS = [<bound method Project.set_animtoolkit_UI of <r9project.Project object at 0x000000000BFFA860>>, <bound method Project.set_animtoolkit_UI of <r9project.Project object at 0x000000000BFFA860>>, <bound method Project.set_animtoolkit_UI of <r9project.Project object at 0x000000000BFFA860>>]

Callback globals so you can fire in commands prior to the UI opening, we use this internally to fire an asset sync call on our project pose library and to setup some additional paths.

def myProjectCallback(cls)
cls.poseHandlerPaths=[‘MyProjects/resources/poseHandlers’] cls.posePathProject =’My_projects/global/project/pose/lib’

r9Anim.RED_ANIMATION_UI_OPENCALLBACKS.append(myProjectCallback)

Note

the function calls bound to the callback are passed the current instance of the animUI class as an arg so you can modify as you need. Also when the PoseUI RMB popup menu is built, IF paths in the list cls.poseHandlerPaths are valid, then we bind into that popup all valid poseHandler.py files found the given path. This allow you to add custom handler types and expose them through the UI directly, they will show up in the RMB popup as such: Fingers_poseHandler.py will show as ‘Add Subfolder : FINGERS’

checkRunTimeCmds()

Ensure the RedRuntime Command plugin is loaded.

getChannelBoxSelection()

return a list of attributes selected in the ChannelBox

getNodeAttrStatus(node=None, asDict=True, incLocked=True)

stub function/ wrapper of getChannelBoxAttrs as the name is a little misleading and not really what the function is doing in hindsight.

getChannelBoxAttrs(node=None, asDict=True, incLocked=True)

return the status of all attrs on the given node, either as a flat list or a dict. As dict it contains all data which controls the lock, keyable, hidden states etc

statusDict={‘keyable’:attrs, ‘nonKeyable’:attrs, ‘locked’:attrs}

Parameters:
  • node – given node.
  • asDict – True returns a dict with keys ‘keyable’,’locked’,’nonKeyable’ of attrs False returns a list (non ordered) of all attr states.
  • incLocked – True by default - whether to include locked channels in the return (only valid if not asDict)
getSettableChannels(node=None, incStatics=True)

return a list of settable attributes on a given node.

Parameters:
  • node – node to inspect.
  • incStatics – whether to include non-keyable static channels (On by default).

FIXME: BUG some Compound attrs such as constraints return invalid data for some of the base functions using this as they can’t be simply set. Do we strip them here? ie: pointConstraint.target.targetWeight

getAnimLayersFromGivenNodes(nodes)

return all animLayers associated with the given nodes

animLayersConfirmCheck(nodes=None, deleteMerged=True)

return all animLayers associated with the given nodes

Parameters:
  • nodes – nodes to check membership of animLayers. If not pass the check will be at sceneLevel
  • deleteMerged – modifies the warning message
mergeAnimLayers(nodes, deleteBaked=True)

from the given nodes find, merge and remove any animLayers found

FOR THE LOVE OF GOD AUTODESK, fix animLayers and give us a decent api for them, oh, and stop building massive mel commands on the fly based on bloody optVars!!!!

pointOnPolyCmd(nodes)

This is a BUG FIX for Maya’s command wrapping of the pointOnPolyCon which doesn’t support namespaces. This deals with that limitation

eulerSelected()

cheap trick! for selected objects run a Euler Filter and then delete Static curves

animCurveDrawStyle(style='simple', forceBuffer=True, showBufferCurves=False, displayTangents=False, displayActiveKeyTangents=True, *args)

Toggle the state of the graphEditor curve display, used in the Filter and Randomizer to simplify the display and the curve whilst processing. This allows you to also pass in the state directly, used by the UI close event to return the editor to the last cached state

animRangeFromNodes(nodes, setTimeline=True)

return the extend of the animation range for the given objects :param nodes: nodes to examine for animation data :param setTimeLine: whether we should set the playback timeline to the extent of the found anim data

timeLineRangeGet(always=True)

Return the current PlaybackTimeline OR if a range is selected in the TimeLine, (Highlighted in Red) return that instead.

Parameters:always – always return a timeline range, if none selected return the playbackRange.
Return type:tuple
Returns:(start,end)
timeLineRangeProcess(start, end, step, incEnds=True)

Simple wrapper function to take a given framerange and return a list[] containing the actual keys required for processing. This manages whether the step is negative, if so it reverses the times. Basically just a wrapper to the python range function.

selectKeysByRange(nodes=None, animLen=False)

select the keys from the selected or given nodes within the current timeRange or selectedTimerange

setTimeRangeToo(nodes=None, setall=True)

set the playback timerange to be the animation range of the selected nodes. AnimRange is determined to be the extent of all found animation for a given node

class AnimationLayerContext(srcNodes, mergeLayers=True, restoreOnExit=True)

Bases: object

Context Manager for merging animLayers down and restoring the data as is afterwards

class AnimationUI(dockUI=True)

Bases: object

classmethod show()
setPoseSelected(val=None, *args)

set the PoseSelected cache for the UI calls

getPoseSelected()
buildPoseList(sortBy='name')

Get a list of poses from the PoseRootDir, this allows us to filter much faster as it stops all the os calls, cached list instead

buildFilteredPoseList(searchFilter)

build the list of poses to show in the poseUI TODO: hook up an order based by date in here as an option to tie into the UI

getPoseSubFolder()

Return the given pose subFolder if set

getPoseDir()

Return the poseDir including subPath

getPosePath()

Return the full posePath for loading

getIconPath()

Return the full posePath for loading

addPopupMenus_PoseHandlers(parentPopup)

for a given list of folders containing poseHandler files add these as default ‘make subfolder’ types to the main poseUI popup menu

addPopupMenusFromFolderConfig(parentPopup)

if the poseFolder has a poseHandler.py file see if it has the ‘posePopupAdditions’ func and if so, use that to extend the standard menu’s

class AnimFunctions(filterSettings=None, **kws)

Bases: object

Most of the main Animation Functions take a settings object which is responsible for hierarchy processing. See r9Core.FilterNode and r9Core.Filter_Settings for more details. These are then passed to the r9Core.MatchedNodeInputs class which is designed specifically to process two hierarchies and filter them for matching pairs. What this means is that all the anim functions deal with hierarchies in the same manor making it very simple to extend.

Generic filters passed into r9Core.MatchedNodeInputs class:
  • setting.nodeTypes: list[] - search for child nodes of type (wraps cmds.listRelatives types=)
  • setting.searchAttrs: list[] - search for child nodes with Attrs of name
  • setting.searchPattern: list[] - search for nodes with a given nodeName searchPattern
  • setting.hierarchy: bool = lsHierarchy code to return all children from the given nodes
  • setting.metaRig: bool = use the MetaRig wires to build the initial Object list up

Note

with all the search and hierarchy settings OFF the code performs a dumb copy, no matching and no Hierarchy filtering, copies using selected pairs obj[0]>obj[1], obj[2]>obj[3] etc

Note

filterSettings is also now bound to the class and if no filterSettings object is passed into any of the calls we use the classes instance instead. Makes coding a lot more simple as you can take an instance of AnimFunctions and just fill it directly before running the functions.

>>> # new functionality
>>> animFunc=AnimFunctions()
>>> animFunc.settings.nodeTypes=['nurbsCurve']
>>> animFunc.settings.searchPattern=['ctrl']
>>> animFunc.copyKeys([srcRootNode, destRootNode])
>>>
>>> # old functionality
>>> settings=r9Core.FilterSettings()
>>> settings.nodeTypes=['nurbsCurve']
>>> settings.searchPattern=['ctrl']
>>> animFunc.copyKeys([srcRootNode, destRootNode], filterSettigns=settings)
copyKeys_ToMultiHierarchy(nodes=None, time=(), pasteKey='replace', attributes=None, filterSettings=None, matchMethod=None, mergeLayers=True, **kws)

This isn’t the best way by far to do this, but as a quick wrapper it works well enough. Really we need to process the nodes more intelligently prior to sending data to the copyKeys calls

copyKeys(nodes=None, time=(), pasteKey='replace', attributes=None, filterSettings=None, toMany=False, matchMethod=None, mergeLayers=False, timeOffset=0, **kws)

Copy Keys is a Hi-Level wrapper function to copy animation data between filtered nodes, either in hierarchies or just selected pairs.

Parameters:
  • nodes – List of Maya nodes to process. This combines the filterSettings object and the MatchedNodeInputs.processMatchedPairs() call, making it capable of powerful hierarchy filtering and node matching methods.
  • filterSettings – Passed into the FilterNode code to setup the hierarchy filters see docs on the FilterNode_Settings class’ Note that this is also now bound to the class instance and if not passed in we use this classes instance of filterSettings cls.settings
  • pasteKey – Uses the standard pasteKey option methods - merge,replace, insert etc. This is fed to the internal pasteKey method. Default=replace
  • time – Copy over a given timerange - time=(start,end). Default is to use no timeRange. If time is passed in via the timeLineRange() function then it will consider the current timeLine PlaybackRange, OR if you have a highlighted range of time selected(in red) it’ll use this instead.
  • attributes – Only copy the given attributes[]
  • matchMethod – arg passed to the match code, sets matchMethod used to match 2 node names
  • mergeLayers – this pre-processes animLayers so that we have a single, temporary merged animLayer to extract a compiled version of the animData from. This gets deleted afterwards.

TODO: this needs to support ‘skipAttrs’ param like the copyAttrs does - needed for the snapTransforms calls

copyAttrs_ToMultiHierarchy(nodes=None, attributes=None, skipAttrs=None, filterSettings=None, matchMethod=None, **kws)

This isn’t the best way by far to do this, but as a quick wrapper it works well enough. Really we need to process the nodes more intelligently prior to sending data to the copyKeys calls

copyAttributes(nodes=None, attributes=None, skipAttrs=None, filterSettings=None, toMany=False, matchMethod=None, **kws)

Copy Attributes is a Hi-Level wrapper function to copy Attribute data between filtered nodes, either in hierarchies or just selected pairs.

Parameters:
  • nodes – List of Maya nodes to process. This combines the filterSettings object and the MatchedNodeInputs.processMatchedPairs() call, making it capable of powerful hierarchy filtering and node matching methods.
  • filterSettings – Passed into the FilterNode code to setup the hierarchy filters see docs on the FilterNode_Settings class’ Note that this is also now bound to the class instance and if not passed in we use this classes instance of filterSettings cls.settings
  • attributes – Only copy the given attributes[]
  • skipAttrs – Copy all Settable Attributes OTHER than the given, not used if an attributes list is passed
  • matchMethod – arg passed to the match code, sets matchMethod used to match 2 node names
snapTransform(nodes=None, time=(), step=1, preCopyKeys=1, preCopyAttrs=1, filterSettings=None, iterations=1, matchMethod=None, prioritySnapOnly=False, snapRotates=True, snapTranslates=True, **kws)

Snap objects over a timeRange. This wraps the default hierarchy filters so it’s capable of multiple hierarchy filtering and matching methods. The resulting node lists are snapped over time and keyed. :requires: SnapRuntime plugin to be available

Parameters:
  • nodes – List of Maya nodes to process. This combines the filterSettings object and the MatchedNodeInputs.processMatchedPairs() call, making it capable of powerful hierarchy filtering and node matching methods.
  • filterSettings – Passed into the FilterNode code to setup the hierarchy filters see docs on the FilterNode_Settings class’ Note that this is also now bound to the class instance and if not passed in we use this classes instance of filterSettings cls.settings
  • time – Copy over a given timerange - time=(start,end). Default is to use no timeRange. If time is passed in via the timeLineRange() function then it will consider the current timeLine PlaybackRange, OR if you have a highlighted range of time selected(in red) it’ll use this instead.
  • step – Time Step between processing when using kws[‘time’] range this accepts negative values to run the time backwards if required
  • preCopyKeys – Run a CopyKeys pass prior to snap - this means that all channels that are keyed have their data taken across
  • preCopyAttrs – Run a CopyAttrs pass prior to snap - this means that all channel Values on all nodes will have their data taken across
  • iterations – Number of times to process the frame.
  • matchMethod – arg passed to the match code, sets matchMethod used to match 2 node names
  • prioritySnapOnly – if True ONLY snap the nodes in the filterPriority list withing the filterSettings object = Super speed up!!
  • snapTranslates – only snap the translate data
  • snapRotates – only snap the rotate data

Note

you can also pass the CopyKey kws in to the preCopy call, see copyKeys above

Note

by default when using the preCopyKeys flag we run a temp merge of any animLayers and copy that merged animLayer data for consistency. The layers are restored afterwards

snapValidateResults()

Run through the stored snap values to see if, once everything is processed, all the nodes still match. ie, you snap the Shoulders and strore the results, then at the end of the process you find that the Shoulders aren’t in the same position due to a driver controller shifting it because of hierarchy issues. TO IMPLEMENT

static snap(nodes=None, snapTranslates=True, snapRotates=True)

This takes 2 given transform nodes and snaps them together. It takes into account offsets in the pivots of the objects. Uses the API MFnTransform nodes to calculate the data via a command plugin. This is a stripped down version of the snapTransforms cmd

Parameters:
  • nodes – [src,dest]
  • snapTranslates – snap the translate data
  • snapRotates – snap the rotate data
static stabilizer(nodes=None, time=(), step=1, trans=True, rots=True)

This is designed with 2 specific functionalities: If you have a single node selected it will stabilize it regardless of it’s inputs or parent hierarchy animations If you pass in 2 objects then it will Track B to A (same order as constraints) This is primarily designed to aid in MoCap cleanup and character interactions. This now also allows for Component based track inputs, ie, track this nodes to this poly’s normal

Parameters:
  • nodes – either single (Stabilize) or twin to track
  • time – [start,end] for a frameRange
  • step – int value for frame advance between process runs
  • trans – track translates
  • rots – track rotates
bindNodes(nodes=None, attributes=None, filterSettings=None, bindMethod='connect', matchMethod=None, **kws)

bindNodes is a Hi-Level wrapper function to bind animation data between filtered nodes, either in hierarchies or just selected pairs.

Parameters:
  • nodes – List of Maya nodes to process. This combines the filterSettings object and the MatchedNodeInputs.processMatchedPairs() call, making it capable of powerful hierarchy filtering and node matching methods.
  • filterSettings – Passed into the FilterNode code to setup the hierarchy filters see docs on the FilterNode_Settings class’ Note that this is also now bound to the class instance and if not passed in we use this classes instance of filterSettings cls.settings
  • attributes – Only copy the given attributes[]
  • bindMethod – method of binding the data
  • matchMethod – arg passed to the match code, sets matchMethod used to match 2 node names

TODO: expose this to the UI’s!!!!

static inverseAnimChannels(node, channels, time=None)

really basic method used in the Mirror calls

static inverseAttributes(node, channels)

really basic method used in the Mirror calls

class curveModifierContext(initialUndo=False, undoFuncCache=[], undoDepth=1)

Bases: object

Simple Context Manager to allow modifications to animCurves in the graphEditor interactively by simply managing the undo stack and making sure that selections are maintained NOTE that this is optimized to run with a floatSlider and used in both interactive Randomizer and FilterCurves

Parameters:
  • initialUndo – on first process whether undo on entry to the context manager
  • undoFuncCache – functions to catch in the undo stack
  • undoDepth – depth of the undo stack to go to
undoCall()
class RandomizeKeys

Bases: object

This is a simple implementation of a Key Randomizer, designed to add noise to animations.

TODO: add in methods to generate secades type of flicking randomization, current implementation is too regular.

noiseFunc(initialValue, randomRange, damp)

really simple noise func, maybe I’ll flesh this out at somepoint

classmethod showOptions()
interactiveWrapper(*args)
addNoise(curves, time=(), step=1, currentKeys=True, randomRange=[-1, 1], damp=1, percent=False, keepKeys=False)

Simple noise function designed to add noise to keyframed animation data.

Parameters:
  • curves – Maya animCurves to process
  • time – timeRange to process
  • step – frame step used in the processor
  • currentKeys – ONLY randomize keys that already exists
  • randomRange – range [upper, lower] bounds passed to teh randomizer
  • damp – damping passed into the randomizer
  • keepkeys – if True maintain current keys
curveMenuFunc(*args)
class FilterCurves

Bases: object

classmethod show()
simplifyWrapper(*args)

straight simplify of curves using a managed cmds.simplfy call

resampleCurves(*args)

straight resample of curves using a managed cmds.bakeResults call :param args[0]: this is the step used in the resample

snapAnimCurvesToFrms(*args)

called after the interaction filters, snap

class MirrorHierarchy(nodes=[], filterSettings=None, **kws)

Bases: object

This class is designed to mirror pose and animation data on any given hierarchy. The hierarchy is filtered like everything else in the Red9 pack, using a filterSettings node thats passed into the __init__

>>> mirror=MirrorHierarchy(cmds.ls(sl=True)[0])
>>> # set the settings object to run metaData
>>> mirror.settings.metaRig=True
>>> mirror.settings.printSettings()
>>> mirror.mirrorData(mode='Anim')
>>> # useful code snippets:
>>> # offset all selected nodes mirrorID by 5
>>> mirror=r9Anim.MirrorHierarchy()
>>> mirror.incrementIDs(cmds.ls(sl=True), offset=5)
>>>
>>> # set all the mirror axis on the selected
>>> for node in cmds.ls(sl=True):
>>>     mirror.setMirrorIDs(node,axis='translateX,rotateY,rotateZ')
>>>
>>> # copy mirrorId's from one node to another
>>> for src, dest in zip(srcNodes, destNodes):
>>>     mirror.copyMirrorIDs(src,dest)

TODO: We need to do a UI for managing these marker attrs and the Index lists TODO: allow the mirror block to include an offset so that if you need to inverse AND offset

by 180 to get left and right working you can still do so.
Parameters:
  • nodes – initial nodes to process
  • filterSettings – filterSettings object to process hierarchies
setMirrorIDs(node, side=None, slot=None, axis=None)

Add/Set the default attrs required by the MirrorSystems.

Parameters:
  • node – nodes to take the attrs
  • side – valid values are ‘Centre’,’Left’ or ‘Right’ or 0, 1, 2
  • slot – bool Mainly used to pair up left and right paired controllers
  • axis – eg ‘translateX,rotateY,rotateZ’ simple comma separated string If this is set then it overrides the default mirror axis. These are the channels who have their attribute/animCurve values inversed during mirror. NOT we allow axis to have a null string ‘None’ so it can be passed in blank when needed

Note

slot index can’t be ZERO

deleteMirrorIDs(node)

Remove the given node from the MirrorSystems

copyMirrorIDs(src, dest)

Copy mirrorIDs between nodes, note the nodes list passed in is zipped into pairs This will copy all the mirrorData from src to dest, useful for copying data between systems when the MirrorMap fails due to naming.

incrementIDs(nodes, offset)

offset the mirrorIndex on selected nodes by a given offset

getNodes()

Get the list of nodes to start processing

getMirrorSide(node)

This is an enum Attr to denote the Side of the controller in the Mirror system

getMirrorIndex(node)

get the mirrorIndex, these slots are used to denote matching pairs such that Left and Right Controllers to switch will have the same index

getMirrorCompiledID(node)

This return the mirror data in a compiled mannor for the poseSaver such that mirror data for a node : Center, ID 10 == Center_10

getMirrorAxis(node)

get any custom attributes set at node level to inverse, if none found return the default axis setup in the __init__

Parameters:node – node return the axis from

Note

if mirrorAxis attr has been added to the node but is empty then no axis will be inversed at all. If the attr doesn’t exist then the default inverse axis will be used

getMirrorSets(nodes=None)

Filter the given nodes into the mirrorDict such that {‘Centre’:{id:node,},’Left’:{id:node,},’Right’:{id:node,}}

Parameters:nodes – only process a given list of nodes, else run the filterSettings call from the initial nodes passed to the class
printMirrorDict(short=True)

Pretty print the Mirror Dict

switchPairData(objA, objB, mode='Anim')

take the left and right matched pairs and exchange the animData or poseData across between them

Parameters:
  • objA
  • objB
  • mode – ‘Anim’ or ‘Pose’
makeSymmetrical(nodes=None, mode='Anim', primeAxis='Left')

similar to the mirrorData except this is designed to take the data from an object in one side of the mirrorDict and pass that data to the opposite matching node, thus making the anim/pose symmetrical according to the mirror setups. Really useful for facial setups!

Parameters:
  • nodes – optional specific listy of nodes to process, else we run the filterSetting code on the initial nodes past to the class
  • mode – ‘Anim’ ot ‘Pose’ process as a single pose or an animation
  • primeAxis – ‘Left’ or ‘Right’ whether to take the data from the left or right side of the setup
mirrorData(nodes=None, mode='Anim')

Using the FilterSettings obj find all nodes in the return that have the mirrorSide attr, then process the lists into Side and Index slots before Mirroring the animation data. Swapping left for right and inversing the required animCurves

Parameters:
  • nodes – optional specific listy of nodes to process, else we run the filterSetting code on the initial nodes past to the class
  • mode – ‘Anim’ ot ‘Pose’ process as a single pose or an animation

TODO: Issue where if nodeA on Left has NO key data at all, and nodeB on right does, then nodeB will be left incorrect. We need to clean the data if there are no keys.

saveMirrorSetups(filepath)

Store the mirrorSetups out to file

loadMirrorSetups(filepath, nodes=None, clearCurrent=True, matchMethod='stripPrefix')
class MirrorSetup

Bases: object

classmethod show()
class CameraTracker(fixed=True)
static cameraTrackView(start=None, end=None, step=None, fixed=True, keepOffset=False)

CameraTracker is a simple wrap over the internal viewFit call but this manages the data over time. Works by taking the current camera, in the current 3dView, and fitting it to frame the currently selected objects per frame, or rather per frameStep.

Parameters:
  • start – start frame
  • end – end frame
  • step – frame step to increment between fit
  • fixed – switch between tracking or panning framing fit
  • keepOffset – keep the current camera offset rather than doing a full viewFit
TODO::
add option for cloning the camera rather than using the current directly
classmethod show()
class ReconnectAnimData

Bases: object

classmethod show()
static reConnectReferencedAnimData(*args)

As per my blog posts on Lost Animaton’s see here for details: http://markj3d.blogspot.co.uk/2011/07/lost-animation-when-loading-referenced.html

static reConnectAnimDataBlind(stripNamespace=True, stripLayerNaming=False, *args)

Blind reconnect based on names. As per my blog posts on Lost Animaton’s see here for details: http://markj3d.blogspot.co.uk/2012/09/lost-animation-part2.html

Parameters:
  • stripNamespace – Change this to False if the curves are not in the rootNamespace but in the sameNamespace as the controllers.
  • stripLayerNaming – allows for the additional ‘Merged_Layer_inputB’ naming conventions