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] #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 * 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.