Using MotionBuilder Python To Offset All Animations Within A Scene
Posted On January 7, 2021

Here is a quick script that will allow you to shift/offset all animation keys within a scene. Previously I would do this via story mode or use another technique that would skip over props and/or constraints. This script should shift everything within the scene that is animated.
The script is not good for things like offsetting one character within a scene while leaving other objects/characters alone – this will move everything within the scene.
from pyfbsdk import * ##Get All Animation Nodes Within The Scene def getAnimatedNodes(): animNodes = [] for i in FBSystem().Scene.Components: for property in i.PropertyList: try: if property.IsAnimated() == True: animNodes.extend( [property.GetAnimationNode()] ) except: pass if len(animNodes) != 0: return animNodes ##OffSet A List Of Animation Node By A Desired Number def OffSetAnimation( pAnimated = list, pFrameOffSet = int ): for i in pAnimated: ##Deal With Properties That Have Single FCurve (IK Blends, IK Pull, Ref. Properties, Etc.) try: i.FCurve.KeyOffset( FBTime( 0, 0, 0, pFrameOffSet ) ) except: pass ##Deal With Properties That Have Multiple Nodes (X, Y, Z Axis) try: for n in range( len(i.Nodes) ): if i.Nodes[ n ].KeyCount != 0: i.Nodes[ n ].FCurve.KeyOffset( FBTime( 0, 0, 0, pFrameOffSet ) ) except: pass ##Offset All Animation On A Take So That The Animation Starts At Frame Zero def StartTakeAnimAtFrameZero(): ##Set Scene To 30FPS And Time Line To Show Frames FBPlayerControl().SetTransportFps(FBTimeMode.kFBTimeMode30Frames) FBPlayerControl().TransportTimeFormat = FBTransportTimeFormat.kFBTimeFormatFrame ##Get The Takes Original Info pTakeStart = FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame() pTakeLength = FBSystem().CurrentTake.LocalTimeSpan.GetDuration().GetFrame() ##Offset Animation animatedNodes = getAnimatedNodes() OffSetAnimation( animatedNodes, -pTakeStart ) ##Set Time Line To Reflect The New OffSet FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan( FBTime(0, 0, 0, 0, 0), FBTime(0, 0, 0, pTakeLength, 0) ) FBPlayerControl().Goto( FBTime(0, 0, 0, 0, 0) ) ##Go Through Every Take Within A Scene And Offset The Animation So That They Start On Frame Zero def OffsetAllTakesToFrameZero(): ##Store Current Take ogTake = FBSystem().CurrentTake ##Go Throuhg Every Take Within The Scene And Offset Keys To Start On Frame Zero for take in FBSystem().Scene.Takes: FBSystem().CurrentTake = take StartTakeAnimAtFrameZero() ##Return To The Take We Were On When We Started The Process FBSystem().CurrentTake = ogTake ''' How To Use The Functions ''' ##Example of offsetting an animation by a specific frame amount ##Get the animated nodes within the scene myAnimatedNodes = getAnimatedNodes() ##Offset the animation nodes to start 100 frames later in the time line OffSetAnimation( myAnimatedNodes , 100 ) ##Offset the animation nodes to start 300 frames earlier in the time line OffSetAnimation( myAnimatedNodes , -300 ) ##Offset all keys to start at frame zero StartTakeAnimAtFrameZero() ##Offset all takes within the scene so that keys start at frame zero OffsetAllTakesToFrameZero()
I hope this helps.