Move a Character in MotionBuilder to the World’s Center with Python
With a dozen takes in my Motionbuilder scene and my Character placed at different locations on each take, I decided Python would help me move my Character to the World’s Center.
With raw Mocap data your Character’s Wold Position is all based on the Actors position within the volume during the capture (obvious). When working with a single Character I prefer to have the Character positioned at the World’s Center.
Placing the Character at the World’s Center not only makes the math easier when supporting coverage of angles or distance, but it also keeps the scene organized and clean. Another nice thing is having the animations start frame reside on frame zero.
With Python being my new best friend within MotionBuilder I thought “I can script this!”.
I will go through my script for moving our test Character to the World Center below:
from pyfbsdk import * ##This Will Have To Be Changed To Reflect Your Charcter's Hip Name ##For This Test I Am Using Mia And Her Hips Are "Mia_Ctrl:HipsEffector" lHipsEffector = FBFindModelByLabelName("Mia_Ctrl:HipsEffector") ##Get The Amount Of Frames That Are Within The Active Time Line ''' We Will Need This As We Will Be Shifting Our Data Along The Time Line And We Want To Respect The Original Length Of The Time Line. ''' def GetFrameCount(): ##Goto Start Frame And Store Frame Number FBPlayerControl().GotoStart() GetFrameCount.StartFrame = FBSystem().LocalTime.GetFrame() ##Goto End Frame And Store Frame Number FBPlayerControl().GotoEnd() GetFrameCount.EndFrame = FBSystem().LocalTime.GetFrame() ##Subtract Start Time From End Time To Get Our Time Span GetFrameCount.TimeSpan = GetFrameCount.EndFrame - GetFrameCount.StartFrame ##Create A Story Clip And Translate The Data To Start At The World Center def CreateStoryClip(): ##Create A Track For Our Character: lTrack = FBStoryTrack(FBStoryTrackType.kFBStoryTrackCharacter, FBStory().RootFolder) ##Assign Our Current Character To The Track lTrack.Details.append(FBApplication().CurrentCharacter) ##Name Track lTrack.Label = "Del_Me-PythonStoryClip" ##Insert Current Take In The Newly Created Track CreateStoryClip.lClip = lTrack.CopyTakeIntoTrack( FBSystem().CurrentTake.LocalTimeSpan, FBSystem().CurrentTake ) ##Move On Time Line To Prevent A Mobu Up Date Bug - This Has To Be Done To Ensure We Get The Correct Coordinates For The Hips FBPlayerControl().GotoNextKey() FBSystem().Scene.Evaluate() FBPlayerControl().GotoStart() FBSystem().Scene.Evaluate() ##Set Variable lCiplOffSet Off Of The Current Character's Hips Translational Values lClipOffSet = lHipsEffector.Translation ##Set Variables lClipOffSetX, lClipOffSetY, lClipOffSetZ lClipOffSetX, lClipOffSetY, lClipOffSetZ = lClipOffSet ##Set Variables lClipOffSetX, lClipOffSetY, lClipOffSetZ To Be A Negative Concatenate String lClipOffSetX, lClipOffSetY, lClipOffSetZ = -lClipOffSetX, -lClipOffSetY, -lClipOffSetZ ##Offset Clip To Start At The World Center CreateStoryClip.lClip.Translation = FBVector3d(lClipOffSetX, 0, lClipOffSetZ) def ShiftStoryClip(): ##Move Clip To Start At Frame Zero lMyStartTime = 0 CreateStoryClip.lClip.Start = FBTime(0,0,0,lMyStartTime) ##Set The Time Line To Start At Zero And Be As Long As The GetFrameCount.TimeSpan Value def StartTimeLineAtZero(): ##Set Our Timeline To Be == GetFrameCount.TimeSpan In Length ##FBTime (0, 0, 0, 0, 0) = (Hours, Minutes, Seconds, Frames, Fields) FBSystem().CurrentTake.LocalTimeSpan = FBTimeSpan(FBTime(0, 0, 0, 0, 0), FBTime(0, 0, 0, GetFrameCount.TimeSpan, 0)) def PlotStoryClip(): ##Deal With The User's Sory Mode Activity FBStory().Mute = False ##Plot Options lPlotClipOptions = FBPlotOptions() lPlotClipOptions.ConstantKeyReducerKeepOneKey = False lPlotClipOptions.PlotAllTakes = False lPlotClipOptions.PlotOnFrame = True lPlotClipOptions.PlotPeriod = FBTime( 0, 0, 0, 1 ) lPlotClipOptions.PlotTranslationOnRootOnly = False lPlotClipOptions.PreciseTimeDiscontinuities = False lPlotClipOptions.RotationFilterToApply = FBRotationFilter.kFBRotationFilterUnroll lPlotClipOptions.UseConstantKeyReducer = False ##Plot Story Clip On Current Character lChar = FBApplication().CurrentCharacter lChar.PlotAnimation(FBCharacterPlotWhere.kFBCharacterPlotOnControlRig,lPlotClipOptions ) ##Now To Delete Our Story Clip By Searching For "Del_Me-PythonStoryClip" for eachTrack in FBStory().RootFolder.Tracks: if eachTrack.Name == "Del_Me-PythonStoryClip": eachTrack.FBDelete() else: pass ##Run Functions In The Correct Order def ProcessTake(): GetFrameCount() CreateStoryClip() ShiftStoryClip() StartTimeLineAtZero() PlotStoryClip() ##Process Our Scene ProcessTake()
This was fun! I found I was able to apply a lot of things I had learned over my short time exploring MotionBuilder’s Python Editor. The process (like all challenges) became problematic and solutions took time to figure out, but the sense of accomplishment is always amazing.
I hope this helps.