MotionBuilder Python – Mirror Character Animation Through Story Mode
One of my first posts on this blog showed how to mirror animations via python. The script would set the mirrored option to “ON” for the character and then plot the animation to the Skeleton and then back to the Control Rig – which works. Recently I was asked if there was a way to mirror an animation along a specific axis and there is via Story Mode. In this post I will go over how we can mirror animations via Story Mode using Python scripting in MotionBuilder.
Below you will find the script which uses a currently selected character and copies the data to a new take called “original_take_name-Mirrored”. The script will mirror the character’s data based on the users desired Plane Option (XY, ZY, XZ) by using FBStoryClipMirrorPlane.
import pyfbsdk as fb
##Create A New Take
def CreateMirrorTake():
takeName = fb.FBSystem().CurrentTake.LongName+"_Mirrored"
fb.FBSystem().CurrentTake.CopyTake( takeName )
##Plot The Story Clip
def PlotCharacterClip( character = object ):
lPlotClipOptions = fb.FBPlotOptions()
lPlotClipOptions.ConstantKeyReducerKeepOneKey = False
lPlotClipOptions.PlotAllTakes = False
lPlotClipOptions.PlotOnFrame = True
lPlotClipOptions.PlotPeriod = fb.FBTime( 0, 0, 0, 1 )
lPlotClipOptions.PlotTranslationOnRootOnly = False
lPlotClipOptions.PreciseTimeDiscontinuities = False
lPlotClipOptions.RotationFilterToApply = fb.FBRotationFilter.kFBRotationFilterUnroll
lPlotClipOptions.UseConstantKeyReducer = False
character.PlotAnimation (fb.FBCharacterPlotWhere.kFBCharacterPlotOnSkeleton,lPlotClipOptions )
character.PlotAnimation(fb.FBCharacterPlotWhere.kFBCharacterPlotOnControlRig,lPlotClipOptions )
##Send Character To A Story Clip And Plot The Data Mirrored
def MirrorCharacter( character = object, XY = False, ZY = False, XZ = False ):
if XY == ZY == XZ == False: pass
else:
##Create A Character Stroy Track And Add Currect Take As A Clip
track = fb.FBStoryTrack( fb.FBStoryTrackType.kFBStoryTrackCharacter, fb.FBStory().RootFolder )
track.Details.append( character )
track.CopyTakeIntoTrack( fb.FBSystem().CurrentTake.LocalTimeSpan, fb.FBSystem().CurrentTake )
##Turn Story Mode "ON"
orgStoryMute = fb.FBStory().Mute
if orgStoryMute == True:
fb.FBStory().Mute = False
##Get Mirror Plane Options
if XY == True: mirrorplaneOption = fb.FBStoryClipMirrorPlane.kFBStoryClipMirrorPlaneXY
if ZY == True: mirrorplaneOption = fb.FBStoryClipMirrorPlane.kFBStoryClipMirrorPlaneZY
if XZ == True: mirrorplaneOption = fb.FBStoryClipMirrorPlane.kFBStoryClipMirrorPlaneXZ
##Set All Clips On Provided Track To Be Mirrored
for clip in track.Clips:
clip.SolvingMode = fb.FBStoryClipSolveMode.kFBStoryClipRetargetSkeleton ##Sets The Solving Mode To "RetargetSkeleton" Which Seems To Give Mirrored Result
clip.MirrorPlane = mirrorplaneOption ##Set Mirror Plane Options Based Off Of The User's Checked Box
clip.MirrorAnimation = True
##Plot Mirrored Story Data Back To Take
PlotCharacterClip( character )
##Delete Stroy Track
track.FBDelete()
##Set Story Mute Back To Original Setting
fb.FBStory().Mute = orgStoryMute
CreateMirrorTake()
##Mirror Current Character Along Mirror Plane ZY
MirrorCharacter( fb.FBApplication().CurrentCharacter, XY = False, ZY = True, XZ = False )
I hope this helps.
Nice trick!
Can you help to modification script and made the same for Reversed(change Timewarp Interpolation) animation with story mode?
This script is awesome! Thanks a lot for sharing! 😀