MotionBuilder’s Constraint system and Python.

MotionBuilder’s Constraint system is a must for animators. Weather you are rigging, transferring data or animating – you will want to use a Constraint system to make your life easier. Let’s see how Python can access MotionBuilder’s Constraint system.

Using Python to set up a Constraint system in MotionBuilder took a lot of searching for me. I wanted to perform a task that used a Parent Child Constraint and when I figured out how to get Python to do a Parent Child Constraint it felt amazing!

Below I will show you what I figured out as well as list out all the different MotionBuilder Constraints you can have Python access for you.

First we will set up a script that will create a scene for us with two markers for us to use and then apply a “Parent Child” constraint to them:

from pyfbsdk import *
from pyfbsdk_additions import *

lSystem = FBSystem()
lScene = FBSystem().Scene

# Creating the two objects that will be used for our constraint scipt

#Creat our "lParentMarker" and names it 'ParentMarker'
lParentMarker = FBModelMarker('ParentMarker')
#Set our Marker to be visible
lParentMarker.Show = True
#Set the size of the lParentMarker
lParentMarker.Size = 2500
#Set the "Look" property of the lParentMarker, the end # is the visual stle. See list below to find numeric values for each visual style
lParentMarker.PropertyList.Find('LookUI').Data=1
#Set the color value for the lParentMarker
lParentMarker.Color = FBColor(0,1,1)
#Define the Transaltion to be represented as lParentMarker.Translation
xTrans, yTrans, zTrans = lParentMarker.Translation
#Declare that lParentMarker.Translation can be animated
lParentMarker.Translation.SetAnimated(True)
#postition lParentMarker in the world
lParentMarker.Translation.GetAnimationNode().KeyAdd(FBTime(0,0,0,0), [-200, 150, 0])

#Creat our "lChildMarker" and names it 'ChildMarker'
lChildMarker = FBModelMarker('ChildMarker')
#Set our Marker to be visible
lChildMarker.Show = True
#Set the size of the lChildMarker
lChildMarker.Size = 2500
#Set the "Look" property of the lChildMarker, the end # is the visual stle. See list below to find numeric values for each visual style
lChildMarker.PropertyList.Find('LookUI').Data=1
#Set the color value for the lChildMarker
lChildMarker.Color = FBColor(1,1,0.3)
#Define the Transaltion to be represented as lChildMarker.Translation
xTrans, yTrans, zTrans = lChildMarker.Translation
#Declare that lChildMarker.Translation can be animated
lChildMarker.Translation.SetAnimated(True)
#postition lChildMarker in the world
lChildMarker.Translation.GetAnimationNode().KeyAdd(FBTime(0,0,0,0), [0, 50, 0])


# Go to last frame and then back to the first frame - this is a HACK to update the viewport
'''
If I don't up date the display the objects will stay at 0, 0 ,0 of the world and
when we apply the constraint the two objects will be on top of one and other
'''
FBPlayerControl().GotoEnd()
FBPlayerControl().GotoStart()


# Selecting objects for the Parent Child Constraint
lChildMdl = FBFindModelByLabelName("ChildMarker")
lChildMdl.Selected = True

lParentMdl = FBFindModelByLabelName("ParentMarker")
lParentMdl.Selected = True

def constraint(CONSTRAINT_TYPE = 10, Weight = 100, SNAP = False, child = None , parent = None  ):
    #assign child and parents variables and check if the right amount of items are selected
    if child == None or parent == None:
        selectedModels = FBModelList()
        FBGetSelectedModels (selectedModels, None, True, True)
        if len(selectedModels) <= 1 or len(selectedModels) > 2 :
           FBMessageBox( "Error", "Please select two items", "OK" )
           return
    
    selected_objects = [FBFindObjectByFullName(model.FullName) for model in selectedModels]
    child = selected_objects[0]
    parent = selected_objects[1]
    
    '''
    Here is a List of all the Constraints that can be called (MotoinBuilder 2015)
    
    CONSTRAINT_TYPE_FaceBuilder = 0
    CONSTRAINT_TYPE_FaceBuilderLookat = 1       
    CONSTRAINT_TYPE_HOOK = 2
    CONSTRAINT_TYPE_Limb_Correction = 3
    CONSTRAINT_TYPE_LookAT = 4
    CONSTRAINT_TYPE_Rotation_Feedback = 5
    CONSTRAINT_TYPE_AIM = 6
    CONSTRAINT_TYPE_Display_Error_On_Conrol = 7
    CONSTRAINT_TYPE_Expression = 8
    CONSTRAINT_TYPE_MULTI_REFERENTIAL = 9
    CONSTRAINT_TYPE_PARENT_CHILD = 10
    CONSTRAINT_TYPE_PATH = 11
    CONSTRAINT_TYPE_POSITION = 12
    CONSTRAINT_TYPE_RANGE = 13
    CONSTRAINT_TYPE_RELATION = 14
    CONSTRAINT_TYPE_RIGID_BODY = 15
    CONSTRAINT_TYPE_Roll_Constraint = 16
    CONSTRAINT_TYPE_3_POINTS = 17
    CONSTRAINT_TYPE_ROTATION = 18
    CONSTRAINT_TYPE_SCALE = 19
    CONSTRAINT_TYPE_MAPPING = 20   
    CONSTRAINT_TYPE_Chain_Ik = 21
    CONSTRAINT_TYPE_Skeleton_Binding = 22
       
    '''
    #setting the prefix for the name displayed on the constraint based on its type
    lConstraint_name = "MyPythonScript-Parent_Constraint"
    
    #constraint creation with type and name
    lMyManager = FBConstraintManager()
    #note "10" is being called as it is assigned to "CONSTRAINT_TYPE_PARENT_CHILD"
    lMyCons = lMyManager.TypeCreateConstraint(10)
    lMyCons.Name = lConstraint_name
    
    #adding elements to the constraint slots
    #for index, element in enumerate(selected_objects):
    lMyCons.ReferenceAdd (0, child)
    lMyCons.ReferenceAdd (1, parent)
    
    #setting up the snap option, so the elements will keep their original position
    if SNAP == False:  
      lMyCons.Snap()
    #weight of the constraint
    lMyCons.Weight = 100
    lMyCons.Active = True

#note "10" is being called as it is assigned to "CONSTRAINT_TYPE_PARENT_CHILD" 
constraint(CONSTRAINT_TYPE = 10, Weight = 100, SNAP = False, child = None , parent = None  )

Things to note are the Constraint types list, FBConstraintManager, needing to have the Constraint Active set to “True”, the Weight set to 100 and the Snap set to “False”.

Now that we have all that out of the way we can go on to shortening that above script into a useful tool that will just take our selected objects and apply a Parent Child Constraint to them:

from pyfbsdk import *

#for reference only    
'''
Here is a List of all the Constraints that can be called (MotoinBuilder 2015)

CONSTRAINT_TYPE_FaceBuilder = 0
CONSTRAINT_TYPE_FaceBuilderLookat = 1       
CONSTRAINT_TYPE_HOOK = 2
CONSTRAINT_TYPE_Limb_Correction = 3
CONSTRAINT_TYPE_LookAT = 4
CONSTRAINT_TYPE_Rotation_Feedback = 5
CONSTRAINT_TYPE_AIM = 6
CONSTRAINT_TYPE_Display_Error_On_Conrol = 7
CONSTRAINT_TYPE_Expression = 8
CONSTRAINT_TYPE_MULTI_REFERENTIAL = 9
CONSTRAINT_TYPE_PARENT_CHILD = 10
CONSTRAINT_TYPE_PATH = 11
CONSTRAINT_TYPE_POSITION = 12
CONSTRAINT_TYPE_RANGE = 13
CONSTRAINT_TYPE_RELATION = 14
CONSTRAINT_TYPE_RIGID_BODY = 15
CONSTRAINT_TYPE_Roll_Constraint = 16
CONSTRAINT_TYPE_3_POINTS = 17
CONSTRAINT_TYPE_ROTATION = 18
CONSTRAINT_TYPE_SCALE = 19
CONSTRAINT_TYPE_MAPPING = 20   
CONSTRAINT_TYPE_Chain_Ik = 21
CONSTRAINT_TYPE_Skeleton_Binding = 22
   
'''

def constraint(CONSTRAINT_TYPE = 10, Weight = 100, SNAP = False, child = None , parent = None  ):
    #assign child and parents variables and check if the right amount of items are selected
    if child == None or parent == None:
        selectedModels = FBModelList()
        FBGetSelectedModels (selectedModels, None, True, True)
        #if we do not have the correct amount of objects selected then warn the usser
        if len(selectedModels) &lt;= 1 or len(selectedModels)&gt; 2 :
           FBMessageBox( "Error", "Please select two items", "OK" )
           return
    
    selected_objects = [FBFindObjectByFullName(model.FullName) for model in selectedModels]
    
    # define which objects your selected objects are child and which are parent
    '''
    currently the script works as so that
    firt object selected = child
    second object selected = parent
        
    first object selected = selected_object[0]
    second object selected = selected_objectp[1]
        
    so if you have
    child = selected_objects[0] then the first obeject selected will be used as your child
    parent = selected_objects[0] then the first obeject selected will be used as your parent
    
    it is all personal taste - I perfer thinking like "I want this object to be the child of this other object"
    when I select my objectw within my scene
    '''
    child = selected_objects[0]
    parent = selected_objects[1]

    #setting the prefix for the name displayed on the constraint based on its type
    lConstraint_name = "MyPythonScript-Parent_Constraint"
    
    #constraint creation with type and name
    lMyManager = FBConstraintManager()
    #note "10" is being called as it is assigned to "CONSTRAINT_TYPE_PARENT_CHILD"
    lMyCons = lMyManager.TypeCreateConstraint(10)
    lMyCons.Name = lConstraint_name
    
    #adding elements to the constraint slots
    #for index, element in enumerate(selected_objects):
    lMyCons.ReferenceAdd (0, child)
    lMyCons.ReferenceAdd (1, parent)
    
    #setting up the snap option, so the elements will keep their position
    if SNAP == False:  
      lMyCons.Snap()
    #weight of the constraint
    lMyCons.Weight = 100
    lMyCons.Active = False
    lMyCons.Snap()

#note "10" is being called as it is assigned to "CONSTRAINT_TYPE_PARENT_CHILD" 
constraint(CONSTRAINT_TYPE = 10, Weight = 100, SNAP = False, child = None , parent = None  ) 

You can easily set this script up to be triggered by a button within your scene, to learn that you can go here and read my Creat a Button in MotionBuilder with Python.

As I mentioned at the start of this post, figuring out how to get Constraints to work through Python took quite a bit of research for me and it was awesome when I was able to finally get the script to work.

I hope this helps.

Leave a reply:

Your email address will not be published.

Site Footer