Hi, is there a premade way in mgear to flip an animation in a time range and not just a single pose? Or has someone made a script to do this? I guess its not enough to simply loop through all keyframes in a time range and flip them? Because the handles of the animation curves might not get flipped?
I do not know of a premade script, but yes in theory. You should be able to loop through the keys on a range and flip pose per frame/key.
It really depends on the setup of the rig and how well it translates to being flipped via a script.
for current_key in frame_range; flip(all_controls); set_key();
How I imagine it would go.
I see, thank you. I’ll give it a try! I think I also might have to find a way to get the state / length / rotation of the tangents of the keys to apply them after flipping. Otherwise the animation curves won’t be the same.
I believe Animbot can do this.
I would rather not tie rig functionality to a subscription service :(. I’ll try to write a script and post it here.
I wrote a first version of a script that will flip the animation of a mgear rig in the current playback range. I am not a programmer, so suggestions for improvements are very welcome :).
It does not flip the values of the extra attributes in the hostUI controllers and gives a warning. Not sure how I can get this to work.
Warning: Flip/Mirror pose fail #
Traceback (most recent call last):
File "C:\Users\Martin\Documents\maya\modules\scripts\mgear\core\anim_utils.py", line 976, in mirrorPose
mirrorEntries.extend(gatherMirrorData(nameSpace, oSel, flip))
File "C:\Users\Martin\Documents\maya\modules\scripts\mgear\core\anim_utils.py", line 1036, in gatherMirrorData
return calculateMirrorData(node, oTarget, flip=flip)
File "C:\Users\Martin\Documents\maya\modules\scripts\mgear\core\anim_utils.py", line 1085, in calculateMirrorData
flipVal = targetNode.attr(attrName).get()
File "C:\Program Files\Autodesk\Maya2018\Python\lib\site-packages\pymel\core\nodetypes.py", line 2009, in attr
raise e
MayaAttributeError: Maya Attribute does not exist (or is not unique):: u'legUI_L0_ctl.leg_R0_ctl'
Maya Attribute does not exist (or is not unique):: u'legUI_L0_ctl.leg_R0_ctl'
Another limitation is that it only works without namespaces right now.
I also had to call the mgear mirrorPose() function for each controller separately in a for loop, because it does not flip the pose with a list as an input and gives the following error / warning when I call it :
Warning: Flip/Mirror pose fail #
Traceback (most recent call last):
File "C:\Users\Martin\Documents\maya\modules\scripts\mgear\core\anim_utils.py", line 972, in mirrorPose
nameSpace = getNamespace(nodes[0])
File "C:\Users\Martin\Documents\maya\modules\scripts\mgear\core\anim_utils.py", line 260, in getNamespace
if len(modelName.split(":")) >= 2:
AttributeError: 'list' object has no attribute 'split'
'list' object has no attribute 'split'
And I commented the function call of “bake_anim_range()” out, because the flip_animation function does not work, if called right after the bake function. It runs until the end, shows no errors, but does not flip the animation. So I have to call them in two steps . Again not sure what I can do about it :).
Here is the script:
import pymel.core as pm
from mgear.core.anim_utils import mirrorPose
class flip_animation():
def __init__(self):
self.rig_grp = 'rigGRP_controllers_grp'
self.controllers = []
self.flip_ctls = []
self.range_start = int(pm.playbackOptions(q=True, min=True))
self.range_end = int(pm.playbackOptions(q=True, max=True))
def get_mgear_controllers(self):
for obj in pm.PyNode(self.rig_grp).members():
if pm.nodeType(obj) != 'objectSet':
self.controllers.append(obj)
if pm.nodeType(obj) == 'objectSet':
for member in obj.members():
self.controllers.append(member)
return self.controllers
def set_flip_controllers(self):
all_ctls_list = [pm.PyNode(x) for x in self.get_mgear_controllers()]
for ctl in all_ctls_list:
if not '_L0_' in str(ctl): # exclude left side to prevent double flipping
self.flip_ctls.append(ctl)
return self.flip_ctls
def bake_anim_range(self):
ctls_list = self.get_mgear_controllers()
pm.bakeResults(
ctls_list,
time=(self.range_start,self.range_end),
preserveOutsideKeys=True,
simulation=True
)
@staticmethod
def flip_pose(ctls_list):
for ctl in ctls_list:
mirrorPose(flip=True, nodes=[ctl])
def set_key(self):
ctls_list = self.get_mgear_controllers()
pm.setKeyframe(ctls_list)
def flip_animation(self):
ctls_list = self.set_flip_controllers()
for frame in range(self.range_start, self.range_end+1):
pm.currentTime(frame)
self.flip_pose(ctls_list)
self.set_key()
if __name__ == '__main__':
flip = flip_animation()
# flip.bake_anim_range()
flip.flip_animation()
Thank you very Much @Miquel !
In the future I would really like to get rid of the baking step, before flipping the animation. But for now I couldn’t figure out how to flip keyframe tangent handles to preserve the animation curves without baking.