def _transferAnimation(self, srcObj, dstObj, attrs = None, mirrorAxis = None, time = None): """ @param srcObj: @param dstObj: @param attrs: @param mirrorAxis: """ maya.cmds.cutKey(dstObj, time=time or ()) if maya.cmds.copyKey(srcObj, time=time or ()): if not time: maya.cmds.pasteKey(dstObj, option='replaceCompletely') else: maya.cmds.pasteKey(dstObj, time=time, option='replace') if attrs is None: attrs = maya.cmds.listAttr(srcObj, keyable=True) or [] for attr in attrs: srcAttribute = mutils.Attribute(srcObj, attr) dstAttribute = mutils.Attribute(dstObj, attr) if dstAttribute.exists(): if dstAttribute.isConnected(): if self.isAttrMirrored(attr, mirrorAxis): maya.cmds.scaleKey(dstAttribute.name(), valueScale=-1, attribute=attr) else: value = srcAttribute.value() self.setAttr(dstObj, attr, value, mirrorAxis)
def _transferAnimation(self, srcObj, dstObj, attrs=None, mirrorAxis=None, time=None): """ :type srcObj: str :type dstObj: str :type attrs: list[str] :type time: list[int] :type mirrorAxis: list[int] """ maya.cmds.cutKey(dstObj, time=time or ()) # remove keys if maya.cmds.copyKey(srcObj, time=time or ()): if not time: maya.cmds.pasteKey(dstObj, option="replaceCompletely") else: maya.cmds.pasteKey(dstObj, time=time, option="replace") if attrs is None: attrs = maya.cmds.listAttr(srcObj, keyable=True) or [] for attr in attrs: srcAttribute = mutils.Attribute(srcObj, attr) dstAttribute = mutils.Attribute(dstObj, attr) if dstAttribute.exists(): if dstAttribute.isConnected(): if self.isAttrMirrored(attr, mirrorAxis): maya.cmds.scaleKey(dstAttribute.name(), valueScale=-1, attribute=attr) else: value = srcAttribute.value() self.setAttr(dstObj, attr, value, mirrorAxis)
def cacheNode(self, srcNode, dstNode, dstAttrs=None, ignoreConnected=None, onlyConnected=None, usingNamespaces=None): """ @type srcNode: mutils.Node @type dstNode: mutils.Node """ mirrorAxis = None mirrorObject = None dstNode.stripFirstPipe() if self.mirrorTable(): mirrorObject = self.mirrorTable().mirrorObject(srcNode.name()) if not mirrorObject: mirrorObject = srcNode.name() log.debug('Cannot find mirror object in pose for %s' % srcNode.name()) mirrorAxis = self.mirrorAxis(mirrorObject) or self.mirrorAxis( srcNode.name()) if mirrorObject and not maya.cmds.objExists(mirrorObject): log.debug('Mirror object does not exist in the scene %s' % mirrorObject) if usingNamespaces: try: dstNode = dstNode.toShortName() except mutils.NoObjectFoundError as msg: log.debug(msg) return except mutils.MoreThanOneObjectFoundError as msg: log.debug(msg) return for attr in self.attrs(srcNode.name()): if dstAttrs and attr not in dstAttrs: continue dstAttribute = mutils.Attribute(dstNode.name(), attr) isConnected = dstAttribute.isConnected() if ignoreConnected and isConnected or onlyConnected and not isConnected: continue type_ = self.attrType(srcNode.name(), attr) value = self.attrValue(srcNode.name(), attr) srcMirrorValue = self.attrMirrorValue(mirrorObject, attr, mirrorAxis=mirrorAxis) srcAttribute = mutils.Attribute(dstNode.name(), attr, value=value, type=type_) dstAttribute.update() self._cache.append((srcAttribute, dstAttribute, srcMirrorValue))
def createObjectData(self, name): """ Create the object data for the given object name. :type name: str :rtype: dict """ attrs = [] # logger.debug(("maya.cmds.ls(name, showType = True) = {0}").format(maya.cmds.ls(name, showType = True))) # [u'Face', u'blendShape'] name_type_list = maya.cmds.ls(name, showType = True) if name_type_list[1] == BLEND_SHAPE_TYPE: attrs = self.getBlendshapeParamList(name) else: attrs = maya.cmds.listAttr(name, keyable = True) or [] attrs = list(set(attrs)) attrs = [mutils.Attribute(name, attr) for attr in attrs] data = {"attrs": self.attrs(name)} for attr in attrs: if attr.isValid(): if attr.value() is None: msg = "Cannot save the attribute %s with value None." logger.warning(msg, attr.fullname()) else: data["attrs"][attr.attr()] = { "type": attr.type(), "value": attr.value() } return data
def listAttr(self, srcObjects = None, dstObjects = None): """ @rtype: list[mutils.Attribute] """ results = [] srcObjects = srcObjects or self.srcObjects dstObjects = dstObjects or self.dstObjects for i, srcObj in enumerate(srcObjects): srcObj = srcObjects[i] dstObj = dstObjects[i] for srcAttr in maya.cmds.listAttr(srcObj, k=True, unlocked=True, scalar=True) or []: srcAttribute = mutils.Attribute(srcObj, srcAttr) dstAttribute = mutils.Attribute(dstObj, srcAttr) results.append((srcAttribute, dstAttribute)) return results
def createObjectData(self, name): """ Create the object data for the given object name. :type name: str :rtype: dict """ attrs = maya.cmds.listAttr(name, unlocked=True, keyable=True) or [] attrs = list(set(attrs)) attrs = [mutils.Attribute(name, attr) for attr in attrs] data = {"attrs": self.attrs(name)} for attr in attrs: if attr.isValid(): if attr.value() is None: msg = "Cannot save the attribute %s with value None." logger.warning(msg, attr.fullname()) else: data["attrs"][attr.attr()] = { "type": attr.type(), "value": attr.value() } return data
def listAttr(node, **kwargs): """ :type node: mutils.Node :type kwargs: dict :rtype: list[mutils.Attribute] """ attrs = maya.cmds.listAttr(node.name(), **kwargs) return [mutils.Attribute(node.name(), attr) for attr in attrs or []]
def test_anim_curve(self): """ Test if get anim curve returns the right value. """ msg = "Incorrect anim curve was returned when using attr.animCurve " attr = mutils.Attribute("sphere", "testFloat") curve = attr.animCurve() assert curve is None, msg + "1" attr = mutils.Attribute("sphere", "testConnected") curve = attr.animCurve() assert curve is None, msg + "2" attr = mutils.Attribute("sphere", "testAnimated") curve = attr.animCurve() assert curve == "sphere_testAnimated", msg + "3"
def test_set_anim_curve(self): """ Test if set anim curve """ msg = "No anim curve was set" attr = mutils.Attribute("sphere", "testAnimated") srcCurve = attr.animCurve() attr = mutils.Attribute("sphere", "testFloat") attr.setAnimCurve(srcCurve, time=(1, 15), option="replace") curve = attr.animCurve() assert curve is not None, msg attr = mutils.Attribute("sphere", "testFloat") attr.setAnimCurve(srcCurve, time=(15, 15), option="replaceCompletely") curve = attr.animCurve() assert curve is not None, msg
def test_attribute_limit3(self): """ Test the minimum attribute limit when setting a keyframe. """ attr = mutils.Attribute("sphere", "testLimit") attr.setKeyframe(-200) value = maya.cmds.keyframe("sphere.testLimit", query=True, eval=True)[0] assert value == -10, "Minimum attibute limit was ignored when setting animation keyframe"
def animCurve(fullname): """ Return the animation curve name for the give attribute. :type fullname: str or None :rtype: str or None """ attribute = mutils.Attribute(fullname) return attribute.animCurve()
def listAttr(node, **kwargs): """ @type node: mutils.Node @type kwargs: {} @rtype: list[Attribute] """ return [ mutils.Attribute(node.name(), attr) for attr in maya.cmds.listAttr(node.name(), **kwargs) or [] ]
def listAttr(name, **kwargs): """ List all the attributes for the given object name. :type name: str :type kwargs: str :rtype: list[mutils.Attribute] """ attrs = maya.cmds.listAttr(name, **kwargs) or [] attrs = list(set(attrs)) return [mutils.Attribute(name, attr) for attr in attrs]
def test_attribute_limit(self): """ Test the attribute limit when setting the attribute value. """ range = (-100, 100) maya.cmds.cutKey("sphere", cl=True, time=range, f=range, at="testLimit") attr = mutils.Attribute("sphere", "testLimit") attr.set(200) value = maya.cmds.getAttr("sphere.testLimit") assert value == 10, "Maximum attibute limit was ignored when setting the attribute value"
def test_non_keyable(self): """ Test if non-keyable attributes can be keyed. """ range = (-100, 100) maya.cmds.cutKey("sphere", cl=True, time=range, f=range, at="testNonKeyable") attr = mutils.Attribute("sphere", "testNonKeyable") attr.setKeyframe(200) value = maya.cmds.keyframe("sphere.testNonKeyable", query=True, eval=True) assert value is None, "Non keyable attribute was keyed"
def listAttr(self, srcObjects=None, dstObjects=None): """ Return the source & destination attributes for the given objects. :rtype: list[(mutils.Attribute, mutils.Attribute)] """ attrs = [] srcObjects = srcObjects or self.srcObjects dstObjects = dstObjects or self.dstObjects for i, srcObj in enumerate(srcObjects): srcObj = srcObjects[i] dstObj = dstObjects[i] srcAttrs = maya.cmds.listAttr(srcObj, keyable=True, unlocked=True, scalar=True) or [] for srcAttr in srcAttrs: srcAttribute = mutils.Attribute(srcObj, srcAttr) dstAttribute = mutils.Attribute(dstObj, srcAttr) attrs.append((srcAttribute, dstAttribute)) return attrs
def createObjectData(self, name): """ @type name: name @rtype: list[Attribute] """ attrs = maya.cmds.listAttr(name, unlocked=True, keyable=True) or [] attrs = list(set(attrs)) attrs = [ mutils.Attribute(name, attr) for attr in attrs ] result = {'attrs': self.attrs(name)} for attr in attrs: if attr.isValid(): result['attrs'][attr.attr()] = {'type': attr.type(), 'value': attr.value()} return result
def test_set_static_keyframe(self): """ Test set static keyframes """ msg = "The inserted static keys have different values" attr = mutils.Attribute("sphere", "testAnimated", cache=False) attr.setStaticKeyframe(value=2, time=(4, 6), option="replace") maya.cmds.currentTime(4) value1 = attr.value() maya.cmds.currentTime(6) value2 = attr.value() assert value1 == value2, msg
def createObjectData(self, name): """ :type name: name :rtype: list[Attribute] """ attrs = maya.cmds.listAttr(name, unlocked=True, keyable=True) or [] attrs = list(set(attrs)) attrs = [mutils.Attribute(name, attr) for attr in attrs] result = {"attrs": self.attrs(name)} for attr in attrs: if attr.isValid(): if attr.value() is None: logger.warning("Cannot save the attribute %s with value None." % attr.fullname()) else: result["attrs"][attr.attr()] = {"type": attr.type(), "value": attr.value()} return result
def load(self, objects=None, namespaces=None, attrs=None, startFrame=None, sourceTime=None, option=None, connect=False, mirrorTable=None, currentTime=None): """ Load the animation data to the given objects or namespaces. :type objects: list[str] :type namespaces: list[str] :type startFrame: int :type sourceTime: (int, int) :type attrs: list[str] :type option: PasteOption :type currentTime: bool """ connect = bool(connect) if option is None or option == PasteOption.ReplaceAll: option = PasteOption.ReplaceCompletely objects = objects or [] logger.debug( 'Animation.load(objects=%s, option=%s, namespaces=%s, srcTime=%s, currentTime=%s)' % (len(objects), str(option), str(namespaces), str(sourceTime), str(currentTime))) srcObjects = self.objects().keys() if mirrorTable: self.setMirrorTable(mirrorTable) valid = False matches = list( mutils.matchNames(srcObjects=srcObjects, dstObjects=objects, dstNamespaces=namespaces)) for srcNode, dstNode in matches: if dstNode.exists(): valid = True break if not matches or not valid: raise mutils.NoMatchFoundError( 'No objects match when loading data') srcCurves = self.open() try: maya.cmds.flushUndo() maya.cmds.undoInfo(openChunk=True) if currentTime and startFrame is None: startFrame = int(maya.cmds.currentTime(query=True)) srcTime = findFirstLastKeyframes(srcCurves, sourceTime) dstTime = moveTime(srcTime, startFrame) if option != PasteOption.ReplaceCompletely: insertKeyframe(srcCurves, srcTime) for srcNode, dstNode in matches: dstNode.stripFirstPipe() for attr in self.attrs(srcNode.name()): if attrs is not None and attr not in attrs: continue dstAttr = mutils.Attribute(dstNode.name(), attr) srcCurve = self.animCurve(srcNode.name(), attr, withNamespace=True) if not dstAttr.exists(): logger.debug( 'Skipping attribute: The destination attribute "%s.%s" does not exist!' % (dstAttr.name(), dstAttr.attr())) continue if srcCurve is None: type_ = self.attrType(srcNode.name(), attr) value = self.attrValue(srcNode.name(), attr) srcAttr = mutils.Attribute(dstNode.name(), attr, type=type_, value=value) self.setStaticKey(srcAttr, dstAttr, dstTime, option) else: self.setAnimationKey(srcCurve, dstAttr, time=dstTime, option=option, source=srcTime, connect=connect) finally: self.close() maya.cmds.undoInfo(closeChunk=True)
def cacheNode(self, srcNode, dstNode, attrs=None, ignoreConnected=None, onlyConnected=None, usingNamespaces=None): """ Cache the given pair of nodes. :type srcNode: mutils.Node :type dstNode: mutils.Node :type attrs: list[str] or None :type ignoreConnected: bool or None :type onlyConnected: bool or None :type usingNamespaces: none or list[str] """ mirrorAxis = None mirrorObject = None # Remove the first pipe in-case the object has a parent dstNode.stripFirstPipe() srcName = srcNode.name() if self.mirrorTable(): mirrorObject = self.mirrorTable().mirrorObject(srcName) if not mirrorObject: mirrorObject = srcName msg = "Cannot find mirror object in pose for %s" logger.debug(msg, srcName) # Check if a mirror axis exists for the mirrorObject otherwise # check the srcNode mirrorAxis = self.mirrorAxis(mirrorObject) or self.mirrorAxis( srcName) if mirrorObject and not maya.cmds.objExists(mirrorObject): msg = "Mirror object does not exist in the scene %s" logger.debug(msg, mirrorObject) if usingNamespaces: # Try and use the short name. # Much faster than the long name when setting attributes. try: dstNode = dstNode.toShortName() except mutils.NoObjectFoundError as msg: logger.debug(msg) return except mutils.MoreThanOneObjectFoundError as msg: logger.debug(msg) return for attr in self.attrs(srcName): if attrs and attr not in attrs: continue dstAttribute = mutils.Attribute(dstNode.name(), attr) isConnected = dstAttribute.isConnected() if (ignoreConnected and isConnected) or (onlyConnected and not isConnected): continue type_ = self.attrType(srcName, attr) value = self.attrValue(srcName, attr) srcMirrorValue = self.mirrorValue(mirrorObject, attr, mirrorAxis=mirrorAxis) srcAttribute = mutils.Attribute(dstNode.name(), attr, value=value, type=type_) dstAttribute.update() self._cache.append((srcAttribute, dstAttribute, srcMirrorValue))
def load(self, objects=None, namespaces=None, start=None, sourceTime=None, attrs=None, currentTime=None, option=Option.ReplaceCompletely, connect=False, mirrorTable=None): """ @type objects: list[str] @type namespaces: list[str] @type start: int @type sourceTime: (int, int) @type attrs: list[str] @type option: Option @type currentTime: bool """ if option == Option.ReplaceAll: option = Option.ReplaceCompletely log.debug( 'Animation.load(objects=%s, option=%s, namespaces=%s, srcTime=%s, currentTime=%s)' % (len(objects), str(option), str(sourceTime), str(namespaces), str(currentTime))) if currentTime and start is None: start = maya.cmds.currentTime(query=True) try: srcCurves = self.open() srcObjects = self.objects().keys() srcTime = self.srcTime(sourceTime, srcCurves) dstTime = self.dstTime(srcTime, start) if mirrorTable: self.setMirrorTable(mirrorTable) maya.cmds.flushUndo() maya.cmds.undoInfo(openChunk=True) matches = mutils.matchObjects(srcObjects=srcObjects, dstObjects=objects, dstNamespaces=namespaces) if not matches: raise mutils.NoMatchFoundError( 'No objects match when loading data') if option != Option.ReplaceCompletely: insertSourceKeyframe(srcCurves, srcTime) for srcNode, dstNode in matches: dstNode.stripFirstPipe() for attr in self.attrs(srcNode.name()): if attrs is not None and attr not in attrs: continue dstAttr = mutils.Attribute(dstNode.name(), attr) srcCurve = self.attrCurve(srcNode.name(), attr, withNamespace=True) if not dstAttr.exists(): log.debug( 'Skipping attribute: The destination attribute "%s.%s" does not exist!' % (dstAttr.name(), dstAttr.attr())) continue if srcCurve is None: type_ = self.attrType(srcNode.name(), attr) value = self.attrValue(srcNode.name(), attr) srcAttr = mutils.Attribute(dstNode.name(), attr, type=type_, value=value) self.setStaticKey(srcAttr, dstAttr, dstTime, option) else: self.setAnimationKey(srcCurve, dstAttr, time=dstTime, option=option, source=srcTime, connect=connect) finally: self.close() maya.cmds.undoInfo(closeChunk=True)
# Try to get the short name. Much faster than the long name when setting attributes. try: dstNode = dstNode.toShortName() except mutils.NoObjectFoundError, msg: logger.debug(msg) return except mutils.MoreThanOneObjectFoundError, msg: logger.debug(msg) return for attr in self.attrs(srcNode.name()): if dstAttrs and attr not in dstAttrs: continue dstAttribute = mutils.Attribute(dstNode.name(), attr) isConnected = dstAttribute.isConnected() if (ignoreConnected and isConnected) or (onlyConnected and not isConnected): continue type_ = self.attrType(srcNode.name(), attr) value = self.attrValue(srcNode.name(), attr) srcMirrorValue = self.attrMirrorValue(mirrorObject, attr, mirrorAxis=mirrorAxis) srcAttribute = mutils.Attribute(dstNode.name(), attr, value=value, type=type_)
def save( self, path, time=None, sampleBy=1, fileType="", bakeConnected=True ): """ Save all animation data from the objects set on the Anim object. :type path: str :type time: (int, int) or None :type sampleBy: int :type fileType: str :type bakeConnected: bool :rtype: None """ objects = list(self.objects().keys()) fileType = fileType or DEFAULT_FILE_TYPE if not time: time = mutils.selectedObjectsFrameRange(objects) start, end = time # Check selected animation layers validateAnimLayers() # Check frame range if start is None or end is None: msg = "Please specify a start and end frame!" raise AnimationTransferError(msg) if start >= end: msg = "The start frame cannot be greater than or equal to the end frame!" raise AnimationTransferError(msg) # Check if animation exists if mutils.getDurationFromNodes(objects or []) <= 0: msg = "No animation was found on the specified object/s! " \ "Please create a pose instead!" raise AnimationTransferError(msg) self.setMetadata("endFrame", end) self.setMetadata("startFrame", start) end += 1 validCurves = [] deleteObjects = [] msg = u"Animation.save(path={0}, time={1}, bakeConnections={2}, sampleBy={3})" msg = msg.format(path, str(time), str(bakeConnected), str(sampleBy)) logger.debug(msg) try: if bakeConnected: maya.cmds.undoInfo(openChunk=True) mutils.bakeConnected(objects, time=(start, end), sampleBy=sampleBy) for name in objects: if maya.cmds.copyKey(name, time=(start, end), includeUpperBound=False, option="keys"): # Might return more than one object when duplicating shapes or blendshapes transform, = maya.cmds.duplicate(name, name="CURVE", parentOnly=True) if not FIX_SAVE_ANIM_REFERENCE_LOCKED_ERROR: mutils.disconnectAll(transform) deleteObjects.append(transform) maya.cmds.pasteKey(transform) attrs = maya.cmds.listAttr(transform, unlocked=True, keyable=True) or [] attrs = list(set(attrs) - set(['translate', 'rotate', 'scale'])) for attr in attrs: dstAttr = mutils.Attribute(transform, attr) dstCurve = dstAttr.animCurve() if dstCurve: dstCurve = maya.cmds.rename(dstCurve, "CURVE") deleteObjects.append(dstCurve) srcAttr = mutils.Attribute(name, attr) srcCurve = srcAttr.animCurve() if srcCurve: preInfinity = maya.cmds.getAttr(srcCurve + ".preInfinity") postInfinity = maya.cmds.getAttr(srcCurve + ".postInfinity") curveColor = maya.cmds.getAttr(srcCurve + ".curveColor") useCurveColor = maya.cmds.getAttr(srcCurve + ".useCurveColor") maya.cmds.setAttr(dstCurve + ".preInfinity", preInfinity) maya.cmds.setAttr(dstCurve + ".postInfinity", postInfinity) maya.cmds.setAttr(dstCurve + ".curveColor", *curveColor[0]) maya.cmds.setAttr(dstCurve + ".useCurveColor", useCurveColor) if maya.cmds.keyframe(dstCurve, query=True, time=(start, end), keyframeCount=True): self.setAnimCurve(name, attr, dstCurve) maya.cmds.cutKey(dstCurve, time=(MIN_TIME_LIMIT, start - 1)) maya.cmds.cutKey(dstCurve, time=(end + 1, MAX_TIME_LIMIT)) validCurves.append(dstCurve) fileName = "animation.ma" if fileType == "mayaBinary": fileName = "animation.mb" mayaPath = os.path.join(path, fileName) posePath = os.path.join(path, "pose.json") mutils.Pose.save(self, posePath) if validCurves: maya.cmds.select(validCurves) logger.info("Saving animation: %s" % mayaPath) maya.cmds.file(mayaPath, force=True, options='v=0', type=fileType, uiConfiguration=False, exportSelected=True) self.cleanMayaFile(mayaPath) finally: if bakeConnected: # HACK! Undo all baked connections. :) maya.cmds.undoInfo(closeChunk=True) maya.cmds.undo() elif deleteObjects: maya.cmds.delete(deleteObjects) self.setPath(path)
def load(self, objects=None, namespaces=None, attrs=None, startFrame=None, sourceTime=None, option=None, connect=False, mirrorTable=None, currentTime=None): """ Load the animation data to the given objects or namespaces. :type objects: list[str] :type namespaces: list[str] :type startFrame: int :type sourceTime: (int, int) :type attrs: list[str] :type option: PasteOption :type connect: bool :type mirrorTable: mutils.MirrorTable :type currentTime: bool or None """ connect = bool(connect) # Make false if connect is None if option is None or option == PasteOption.ReplaceAll: option = PasteOption.ReplaceCompletely objects = objects or [] logger.debug( "Animation.load(objects=%s, option=%s, namespaces=%s, srcTime=%s, currentTime=%s)" % (len(objects), str(option), str(namespaces), str(sourceTime), str(currentTime))) srcObjects = self.objects().keys() if mirrorTable: self.setMirrorTable(mirrorTable) valid = False matches = list( mutils.matchNames(srcObjects=srcObjects, dstObjects=objects, dstNamespaces=namespaces)) for srcNode, dstNode in matches: if dstNode.exists(): valid = True break if not matches or not valid: text = "No objects match when loading data. " \ "Turn on debug mode to see more details." raise mutils.NoMatchFoundError(text) # Load the animation data. srcCurves = self.open() try: maya.cmds.flushUndo() maya.cmds.undoInfo(openChunk=True) if currentTime and startFrame is None: startFrame = int(maya.cmds.currentTime(query=True)) srcTime = findFirstLastKeyframes(srcCurves, sourceTime) dstTime = moveTime(srcTime, startFrame) if option != PasteOption.ReplaceCompletely: insertKeyframe(srcCurves, srcTime) for srcNode, dstNode in matches: # Remove the first pipe in-case the object has a parent dstNode.stripFirstPipe() for attr in self.attrs(srcNode.name()): # Filter any attributes if the parameter has been set if attrs is not None and attr not in attrs: continue dstAttr = mutils.Attribute(dstNode.name(), attr) srcCurve = self.animCurve(srcNode.name(), attr, withNamespace=True) # Skip if the destination attribute does not exists. if not dstAttr.exists(): logger.debug( 'Skipping attribute: The destination attribute "%s.%s" does not exist!' % (dstAttr.name(), dstAttr.attr())) continue if srcCurve: dstAttr.setAnimCurve(srcCurve, time=dstTime, option=option, source=srcTime, connect=connect) else: value = self.attrValue(srcNode.name(), attr) dstAttr.setStaticKeyframe(value, dstTime, option) finally: self.close() maya.cmds.undoInfo(closeChunk=True) # Return the focus to the Maya window maya.cmds.setFocus("MayaWindow")
def save(self, path, time=None, sampleBy=1, fileType="", bakeConnected=True): """ Save all animation data from the objects set on the Anim object. :type path: str :type time: (int, int) or None :type sampleBy: int :type fileType: str :type bakeConnected: bool :rtype: None """ objects = self.objects().keys() logger.debug(("objects = {0}").format(objects)) fileType = fileType or DEFAULT_FILE_TYPE if not time: time = mutils.selectedObjectsFrameRange(objects) start, end = time # Check selected animation layers validateAnimLayers() # Check frame range if start is None or end is None: msg = "Please specify a start and end frame!" raise AnimationTransferError(msg) if start >= end: msg = "The start frame cannot be greater than or equal to the end frame!" raise AnimationTransferError(msg) # Check if animation exists if mutils.getDurationFromNodes(objects or []) <= 0: msg = "No animation was found on the specified object/s! " \ "Please create a pose instead!" raise AnimationTransferError(msg) self.setMetadata("endFrame", end) self.setMetadata("startFrame", start) end += 1 validCurves = [] # deleteObjects = [] # msg = u"Animation.save(path={0}, time={1}, bakeConnections={2}, sampleBy={3})" # msg = msg.format(path, str(time), str(bakeConnected), str(sampleBy)) # logger.debug(msg) try: if bakeConnected: maya.cmds.undoInfo(openChunk=True) mutils.bakeConnected(objects, time=(start, end), sampleBy=sampleBy) for name in objects: if maya.cmds.copyKey(name, time=(start, end), includeUpperBound=False, option="keys"): attrs = maya.cmds.listAttr( name, unlocked=True, keyable=True) or [] attrs = list( set(attrs) - set(['translate', 'rotate', 'scale'])) self.listAttachedAnimCurves(name) for attr in attrs: dstAttr = mutils.Attribute(name, attr) dstCurve = dstAttr.animCurve() logger.debug(("dstCurve = {0}").format(dstCurve)) if dstCurve: srcAttr = mutils.Attribute(name, attr) srcCurve = srcAttr.animCurve() if maya.cmds.keyframe(dstCurve, query=True, time=(start, end), keyframeCount=True): self.setAnimCurve(name, attr, dstCurve) validCurves.append(dstCurve) fileName = "animation.ma" if fileType == "mayaBinary": fileName = "animation.mb" mayaPath = os.path.join(path, fileName) posePath = os.path.join(path, "pose.json") mutils.Pose.save(self, posePath) if validCurves: maya.cmds.select(validCurves) logger.info("Saving animation: %s" % mayaPath) maya.cmds.file(mayaPath, force=True, options='v=0', type=fileType, uiConfiguration=False, exportSelected=True) self.cleanMayaFile(mayaPath) finally: if bakeConnected: # HACK! Undo all baked connections. :) maya.cmds.undoInfo(closeChunk=True) maya.cmds.undo() self.setPath(path)