Scaling And Moving Story Clips With MotionBulider Python

 

After the last two posts (found here and here), I was able to quickly create a script that would scale all selected takes within a scene to a specific frame length.

This could be handy if data needed to blend or needed to conform to a specific length for game play.

The script is easy enough to use, just execute it within your scene then select the takes you wish it to be applied on and type within the python console  ScaleTakes(length).

ie: ScaleTakes(15) will scale all selected takes to 15 frames.

As a bonus all layers on the take will be merged together, the clip will be moved to start on frame zero (if it did not already) and your time line length will be adjusted to fit the new length.

import pyfbsdk as fb
import pyfbsdk_additions as fba
import decimal

##Scene Refresh Bug Work Around
def SceneRefresh(): 
    fb.FBPlayerControl().GotoNextKey()
    fb.FBSystem().Scene.Evaluate()
    fb.FBPlayerControl().GotoPreviousKey()
    fb.FBSystem().Scene.Evaluate()

##Get Length Of Time Line / Get Time Line Frame Count            
def GetTimeSpan():
    return ( fb.FBSystem().CurrentTake.LocalTimeSpan.GetStop().GetFrame() - fb.FBSystem().CurrentTake.LocalTimeSpan.GetStart().GetFrame() )

##Set Time Line Length ie. SetTimeSpan(150, 200) Will Set The Time Line To Start At Frame 150 And End At Frame 200
def SetTimeSpan(start, end):
    fb.FBSystem().CurrentTake.LocalTimeSpan = fb.FBTimeSpan(fb.FBTime(0, 0, 0, start, 0), fb.FBTime(0, 0, 0, end, 0))

##Plot Clip
def PlotStoryClip():
    ##Deal With The User's Sory Mode Activity
    fb.FBStory().Mute = False
    SceneRefresh()
    
    ##Plot Options
    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
    ##Plot Story Clip On Current Character
    lChar = fb.FBApplication().CurrentCharacter               
    lChar.PlotAnimation(fb.FBCharacterPlotWhere.kFBCharacterPlotOnControlRig,lPlotClipOptions )

##Go Through The Story And Delete The Track Created By This Script        
def CleanStoryTrack():       
    for eachTrack in fb.FBStory().RootFolder.Tracks:
        if "--Del_Me-PythonStoryClip" in eachTrack.Name:
            eachTrack.FBDelete()
        else:
            pass


def ScaleTakes(length):
    lTakeLst = []
    ##Add Every Selected Take Within Our Scene To Our Take List
    for i in range( len(fb.FBSystem().Scene.Takes) ):
        if fb.FBSystem().Scene.Takes[i].Selected == True:
            lTakeLst.extend([fb.FBSystem().Scene.Takes[i]])
        else: pass
    ogTake = fb.FBSystem().CurrentTake
    ##Delete Every Take Within Our Take List    
    for take in lTakeLst:
        fb.FBSystem().CurrentTake = take
        fb.FBSystem().CurrentTake.MergeLayers(fb.FBAnimationLayerMergeOptions.kFBAnimLayerMerge_AllLayers_CompleteScene, True, fb.FBMergeLayerMode.kFBMergeLayerModeAutomatic)
        lTrack = fb.FBStoryTrack(fb.FBStoryTrackType.kFBStoryTrackCharacter, fb.FBStory().RootFolder)
        lTrack.Label = fb.FBSystem().CurrentTake.Name + "--Del_Me-PythonStoryClip"
        lTrack.Details.append(fb.FBApplication().CurrentCharacter)
        lTrack.CopyTakeIntoTrack( fb.FBSystem().CurrentTake.LocalTimeSpan, fb.FBSystem().CurrentTake )
        for clip in lTrack.Clips:
            ##Get Clips New End Frame
            oClipStopFrame = GetTimeSpan()
            ##Create Our Adjustment Speed (Clips Current Legnth / Our Desired Length)
            adjSpeed = round( ( decimal.Decimal(oClipStopFrame) / decimal.Decimal(length) ) , 4 )
            ##Set StopFrame So Anim Does Not Get Cut Off
            clip.Stop = fb.FBTime(0,0,0,(length+1))
            ##Set Our Clips New Speed To Be Our Adjustment Speed
            clip.Speed = adjSpeed
            ##Set Our Time Span To Match Our Desired Time Line Length
            SetTimeSpan( 0, length )
        
        PlotStoryClip()
        CleanStoryTrack()
            
    fb.FBSystem().CurrentTake = ogTake

I hope this post does two things;
1. Shows how having a library of functions at your disposal can speed up your scripting
2. Gives you a new toy/tool to play with.

As always, I hope this helps.

2 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.