Using MotionBuilder Python To Offset All Animations Within A Scene

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.

5 Comments

Add a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.