Python Scripting in MotionBuilder – 01 – pyfbsdk and Hello, Cubes


Let’s do some Python scripting in MotionBuilder. Here we’ve got an empty scene. Our goal with
this first tutorial is simply to fumble around with the Python API in MotionBuilder to get
a basic familiarity with it. So let’s start by opening a Python Editor from the Window
menu. This provides us with a very basic text editor
for writing Python scripts, and it also serves as an interactive prompt. If you highlight
a piece of code and press Ctrl+Enter (or just Enter on the numpad), that code will be evaluated,
and standard output will be printed to the console window above. Note that this window doesn’t print the results
of the evaluation, so you’ll always have to include an explicit print statement if you
want something displayed. The first thing you’ll want to do in writing
any MotionBuilder script is to import the MotionBuilder API. We do this with the line: from pyfbsdk import * This isn’t necessary when doing interactive
evaluation like we are here, so if you’re just messing around or writing a one-off script,
you don’t need to bother with it. However, it’s required in other contexts, so it’s good
to include as a rule. There’s one more module that provides some
extra functionality, mostly UI-related, that’s written in Python, and accessible only to
Python. That’s called pyfbsdk_additions, and we would import it in the same way, but we
don’t need it right now. Let’s pick this statement apart briefly. pyfbsdk
is the name of a python module which serves as a wrapper for the MotionBuilder SDK. This
library and all of its classes carry the legacy ‘FB’ abbreviation, since back in the day,
MotionBuilder was known as Kaydara Filmbox. If we were to import this module directly,
we could see that it’s stored as a .pyd file within our MotionBuilder installation’s Python
library directory. If you’re a beginner, it’s important to have
some familiarity with what’s called the PATH. The PATH is an ordered list of directories
containing Python modules. Whenever we import something by name, Python examines each directory
in the PATH until it finds a module matching the name we give. This list can be modified
in a number of ways to allow your own modules to be found, but we can discuss that in more
detail later. For now, notice that despite its elevated
importance with respect to Python scripting in MotionBuilder, pyfbsdk is just another
Python module, and we’re able to import it because it’s in the PATH. As a final note, you may notice that we’re
using an asterisk in our import statement. This takes every symbol that’s defined in
the pyfbsdk module and dumps it into our current namespace. Using this kind of import is ordinarily
considered bad practice, but we can make an exception for this module. Anyway, now that we’ve imported pyfbsdk, we
have access to all the classes that it defines. There are a lot of them, and we won’t cover
any of them in detail here, but since we’ve come this far, let’s get to a very simple
example. There’s rarely a practical reason to create
cube models in an actual MotionBuilder script, so let’s get that out of the way as our sort
of ‘Hello World’ example. If we want to make a cube, the class for that
is FBModelCube. We call the constructor of that class to create a new cube. You’ll notice that if we call the constructor
with no arguments, we get an error. I’ll explain the details of this error later, but for now
just recognize that the error is telling us that we need to pass in a string. In this
case, that string represents the name we’d like our cube to have. Now our code executes successfully, and we
can see from the Navigator that we have a new model in the scene. However, our new cube
isn’t being shown, and if we check its properties, we can see that its Show property is set to
False. This is the case by default for all models that we create procedurally, so we’ll
need to add another line to set Show to True if we want it shown in the viewer. Of course, we haven’t assigned our cube to
a Python variable, which wouldn’t be a very helpful way of doing things in practice. Let’s
delete it and make a new cube, which we’ll explicitly show. The cube is a little small, so let’s scale
it up as well. Here we’re applying a three-component vector,
or FBVector3d, to the Scaling property. If we want to get rid of our cube, we have
the very convenient ability of asking it to delete itself. We do this by calling the FBDelete
method. Also, if we know what a model is named, but
we don’t yet have a reference to it in Python, we can get one by calling FBFindModelByLabelName.
This is a free function that takes an object’s exact name, namespace and all, and returns
that object, or None if no object exists by that name. Now just for fun, let’s write a little function
that will take some parameters and create a cube for us. So we’re going to give this function an X
position, a Y position, and a scaling factor that will be applied uniformly to the cube.
We’ll just generate a throwaway name for the cube based on its position, we’ll create the
cube, we’ll show it… At the end of the function, it would make
to return the cube in case the caller wanted to do something with it. And we’ll also apply our X and Y position
and our scale to the cube. So if we test out this new function, we can
see that it works just fine. And here we’ve created a cube at X position
100, Y position 200, with a uniform scaling value of 50. However, as you may know, the code that we’ve
written here will be indiscriminately executed any time this script is loaded. We wouldn’t
want the simple act of importing a module to cause our scene to be polluted with cubes,
so it’s common practice in Python to include a condition at the bottom of the file that
checks the __name__ variable to tell us the scope in which the script is being executed.
Typically, this is __main__, but you’ll notice that in MotionBuilder, any code that we execute
from the interactive prompt is in the __builtin__ namespace. To cover both of these cases, we can check
__name__ like so: If __name__ equals ‘__main__’ or __name__
equals ‘__builtin__’, run our code. Or more compactly, we can test for inclusion
in a tuple. It’s also good practice to use a main() function
that you just call from this block, if only because it allows you to return from your
script. Finally, let’s make our main function do something
a little more interesting. This rather pointless piece of code here will
create a grid of evenly spaced cubes, with a random scale value between 5 and 10 for
each. And you can see that we’ve imported the random
module so that we can get random numbers. Now if we execute our code again, we get a
lovely wall of cubes. If we ever wanted to run this script again
at a later date, there are a couple of ways we could do that aside from opening the script
in the Python Editor and executing it there. For now, I’ll show you the simplest way, which
is to use the Asset Browser. To make our script accessible from the Asset
Browser, we’ll want to save it somewhere within our MotionBuilder Scripts path. This is in your MotionBuilder installation
directory, under binconfigScripts. If we create a subdirectory and save our new
script to it, it’ll show up in the Asset Browser. Alternatively, and especially if you’re on
a network with multiple users, you could create a scripts directory anywhere you like, and
then add it to the Asset Browser as a favorite path. Now any time we want to run this script, we
can simply find it in the Asset Browser, drag it into the scene, and select ‘Execute.’ That’s it for this brief introduction. In
later videos, we’ll cover some more practical examples of what you can do with Python in
MotionBuilder. Thanks for watching.

Leave a Reply

Your email address will not be published. Required fields are marked *