Using Python to import MotionBuilder Characters into story. 

 

MotionBuilder comes with a great script that will place your selected character into a Character Track within the Story, I wanted to write one that would put all of the scene’s Characters into the story.

Once again I will use the “Mia_Rigged.fbx” file to test my script. I created a NEW scene and merged the “Mia_Rigged.fbx” file twice into that new scene. I checked “Apply NameSpace” and then checked “Use New NameSpace”. For my NameSpace I used “Mia01” for the first Character and “Mia02” on my second merge.

Once I had both my Characters within my scene (Mia01 and Mia02) I did a very quick animation of them sliding back and forth through the world – this allowed me to have some test animation data to work with.

Now let’s start scripting!!! 🙂

First we need to set up the script to find all our Characters within the scene and put them into a list.

from pyfbsdk import *
import re

# Variables --------------------
lSystem = FBSystem()
lScene = FBSystem().Scene
lTakeName = lSystem.CurrentTake.Name
lCurChar = FBApplication().CurrentCharacter

# This variable will split "lCurChar" into only the first word before the ":" in the name = our NameSpace 
lCurCharNameSpace = lCurChar.LongName.rsplit(':', 1)[0]

# the characters within our scene
lCharactersInScene = lScene.Characters

# story
lStory = FBStory()

# Print "hello world!" for every character within the scene 
print "These are the Names of the Characters within your scene:"
for lCurChar in lCharactersInScene:
    print "hello world!"

Ok, above we have some variables that we will be using as well as a simple script that will print “hello world!” once for every character within our scene.

Now that we have the Characters listed let’s put it to actual use and see what info we can get Python to tell us about our Characters.

from pyfbsdk import *
import re

# Variables --------------------
lSystem = FBSystem()
lScene = FBSystem().Scene
lTakeName = lSystem.CurrentTake.Name
lCurChar = FBApplication().CurrentCharacter

# This variable will split "lCurChar" into only the first word before the ":" in the name = our NameSpace 
lCurCharNameSpace = lCurChar.LongName.rsplit(':', 1)[0]

# the characters within our scene
lCharactersInScene = lScene.Characters

# story
lStory = FBStory()

# Print the total number of characters within the scene -----------
lNumberOfChar = len (lCharactersInScene)
print "There Are A Total Of", lNumberOfChar, "Characters within Your Scene"
print "--------------------"

# Print a range for the numeber of characters within the scene
lCharactersList = range (lNumberOfChar)
print "The Characters Listed In The Scene Are:", lCharactersList
print "--------------------" 

# Print Names of all the characters within our scene --------------
print "These are the Names of the Characters within your scene:"
for lCurChar in lCharactersInScene:
    lCurCharNameSpace = lCurChar.LongName.rsplit(':', 1)[0]
    print lCurCharNameSpace
print "--------------------"

So with the above script we found out:

  1. The total number of characters within our scene
  2. The range of numbers for those characters
  3. The NameSpace for each character

The part to really take notice is the variable “lCurCharNameSpace”, note that this is much different from using “lCurChar.Name” and “lCurChar.LongName” which would give us different strings:

  • lCurChar.Name = “Mia”
  • lCurChar.LongName = “Mia01:Mia” or “Mia02:Mia”
  • lCurCharNameSpace = “Mia01” or “Mia02” (this is achieved by taking the LongName version and splitting it to 1 word before the “:”)

Now that we have all of our Character’s info (more than we need, but that’s o.k.), let’s get to dealing with putting the Character’s Data into MotionBuilder’s Story Mode.

We make the same type of list we used to get the Character’s info and we create a loop that will produce our Story setup.

from pyfbsdk import *
import re

# Variables --------------------
lSystem = FBSystem()
lScene = FBSystem().Scene
lTakeName = lSystem.CurrentTake.Name
lCurChar = FBApplication().CurrentCharacter

# This variable will split "lCurChar" into only the first word before the ":" in the name = our NameSpace 
lCurCharNameSpace = lCurChar.LongName.rsplit(':', 1)[0]

# the characters within our scene
lCharactersInScene = lScene.Characters

# story
lStory = FBStory()

# Story Folder will be names after the take the data was one
lParentFolder = FBStoryFolder()
lParentFolder.Label = lSystem.CurrentTake.Name + " StoryFolder"

for lCurChar in lCharactersInScene:
    lCurCharNameSpace = lCurChar.LongName.rsplit(':', 1)[0]
    print lCurCharNameSpace+" is being processed -- "
    
    #Select your Character's Hips: 
    '''
    MAKE SURE THAT YOU KNOW THE NAMESPACE OF YOUR CHARACTER!!!!
    "Mia_Ctrl:HipsEffector" is used because I know that the Character's hips are labled as "NameSpace:Mia_Ctrl:HipsEffector"
    You may need to edit the below line to ensure the script works for your Characters. Select the hips of your Character and see what is needed for you.
    Standardizing your Character's NameSpace will help you creat a fluid pipe line.
    '''
    lCurChar_ChrHips = FBFindModelByLabelName(lCurCharNameSpace+":Mia_Ctrl:HipsEffector") 
    lCurChar_ChrHips.Selected = True
    lCurChar_Track = FBStoryTrack(FBStoryTrackType.kFBStoryTrackCharacter, lParentFolder)
    
    # assign our CurrentCharacter to the track
    lCurChar_Track.Details.append(FBApplication().CurrentCharacter)
    lCurChar_Track.Label = lCurCharNameSpace
    # Insert current take in the newly created track
    lCurChar_Clip = lCurChar_Track.CopyTakeIntoTrack( lSystem.CurrentTake.LocalTimeSpan, lSystem.CurrentTake )

The end result is a Python Script that will create a Story Folder (labeled the same as the take that the script was executed on) and put each Character within the Scene onto their own Character Track (Labeled after the Character’s NameSpace).

The thing to really take note of is NameSpaces. If you do not have a NameSpace naming convention that you stick with then your pipeline will be impossible to maintain and at the very least the script won’t work. 🙂

Once you under stand all this is should be very easy for you to re-create this script to run on all takes (or even selected takes) within your scene. 😉

This was a really fun script for me to figure out.

I hope this helps.

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.