cosmogonies.net Blog of cosmogonies.net

copyrightcontent
5Mar/133

How to batch Motionbuilder: FBX SDK to the rescue.

When I suddently discovered that MotionBuilder does not have a batch mode, I fainted, as I consider doing my job is half the time coding batch tools.

As a reminder, the Batch version of a software is the access of this one in command-line; means without interfaces, but more importantly it is also scriptable so you can process infinite auto-tasks management with it.
Maya comes with a mayabatch.exe, and xsi has its xsibatch.exe, but you can just start MotionBuilder.exe with a -console flag, which allow you having an external output, nothing really fancy.
This is a real issue here: How can building a python framework, multi-environment, and keep tools doing full-auto pipeline processes.
Thankful to Autodesk policy, they gave us a solution : FBX SDK.

  • Explanations:

FBX SDK is written in c++, but hopefully Autodesk managed to wrapped it with SWIG to propose a binding python (if the link is dead, try a search with fbx sdk python binding in Area)
The full doc is actually here, but it is the c++ one. Do not worry about it, python equivalent are found easily (remember dir statement).

So, Is this another environement to my framework: FBX ? Not quite.
We are still in standalone python, but we are using a library to PARSE a file format.
As Maya uses .MA as a 3d structure of succession of MEL Commands, and .MB as a binay, FBX provides both ascii and binary, but ascii fbx are very hard to parse.
FBX SDK help you to read, modify and save any file of FBX, but require only python, ANY python installed on your computer.
For example, I use FBX SDK to open, read, and manage a fbx file, running into a mayabatch.exe (and its mayapy python).
You can also used FBX SDK into MotionBuilder UI, but that is REALLY the snake eating its own tail !

  • Several snippets:

Here I share with you several usefull snippets:


def getHandle(_FilePath):
  import PyFBX
  import PyFBX.fbx

  lSdkManager = PyFBX.fbx.KFbxSdkManager.Create()
  ios = PyFBX.fbx.KFbxIOSettings.Create(lSdkManager, PyFBX.fbx.IOSROOT)
  lImporter = PyFBX.fbx.KFbxImporter.Create(lSdkManager, "")
  lImporter.Initialize(_FilePath, -1, lSdkManager.GetIOSettings())
  MobuFileHandle = PyFBX.fbx.KFbxScene.Create(lSdkManager, "myScene")
  lImporter.Import(MobuFileHandle)
  return MobuFileHandle

If you use that to parse a lot of files, be really sure to free the RAM from
.Import here will literally copy the file into the RAM of your computer, and as the reference is still alive, the garbage collector will not free the RAM.
My advice here is to explicitly calling lSdkManager.Destroy() and recreate a fileHandle from scratch every time you switch from a file to another.


def saveAs(_FBXHandle, _FilePath):
  import PyFBX
  import PyFBX.fbx
  import os.path
  lSdkManager = PyFBX.fbx.KFbxSdkManager.Create()
  ios = PyFBX.fbx.KFbxIOSettings.Create(lSdkManager,PyFBX.fbx.IOSROOT)
  lExporter = PyFBX.fbx.KFbxExporter.Create(lSdkManager,"")
  lExporter.Initialize(_FilePath,-1,lSdkManager.GetIOSettings())
  res = lExporter.Export(_FBXHandle)

  if res and os.path.exists(_FilePath):
    print("File was exported succesfully at ="+_FilePath)

Remember how Motionbuilder manage their types of objects in Navigator Models aside, and all objects ordered by types?
Same thing here in FBX, everything is stored by types first, and you have a Method of Scene for everyone:
Finally, notice how most of them are only accessible with an index, GetCharacter, GetControlSetPlug, GetCharacterPose, GetPose , GetMaterial, GetTexture, GetVideo
Here are some snippets for parsing:


def getVideoFiles(_Scene):
  VideoList=[]
  for currentIdx in range(_Scene.GetVideoCount()):
    VideoList.append( _Scene.GetVideo(currentIdx).GetFileName() )
  return VideoList

def getMaterials(_Scene):
  MaterialList=[]
  for currentIdx in range(_Scene.GetMaterialCount()):
    MaterialList.append( _Scene.GetMaterial(currentIdx) )
  return MaterialList

def getTextures(_Scene):
  TextureList=[]
  for currentIdx in range(_Scene.GetTextureCount()):
    TextureList.append( _Scene.GetTexture(currentIdx) )
  return TextureList

def getChildren(_Node):
  ChildrenList=[]
  for currentIdx in range(_Node.GetChildCount()):
    ChildrenList.append( _Node.GetChild(currentIdx) )
  return ChildrenList

So you can easily explore the graph of a top node:


def getAllNodes(_TopNode):
  import PyFBX
  import PyFBX.fbx
  theNodeList=[]

  def recurseExplore(currentNode):
    print currentNode.GetTypeName(), currentNode.GetName()

    for i in range(currentNode.GetChildCount()):
      cur = currentNode.GetChild(i)
      theNodeList.append(cur)
    recurseExplore(cur)

  recurseExplore(_TopNode)
  return theNodeList
fd = getHandle(r"\\...\Your\Path\FileName.fbx")
test = getAllNodes(fd.GetRootNode())

  • Avoiding traps and shortcuts:

Finally, you can of course look for a specific property.
You have in the doc all the methods for getting rotation or translation in Nodes.
Here is some snippets to get a value of a property by name, for example your own custom ones.


#currentNode= fd.GetRootNode()
value = currentNode.FindProperty(_PropertyName).Get()

But be very careful about not mixing both SDK in your mind!
FBX is NOT Motionbuilder, and experienced python coders in Mobu will find some similarities, but it differs a lot.
For example, forget about .Data member of a node to get its value, but use .Get() method.

Precisely, python in Mobu is called "Open Reality SDK" and is not FBX SDK, but the python package name in mobu, pyfbsdk, can be really confusing (FB prefix comes from FilmBox).
Here are some others examples:


if type(currentNode) == PyFBX.fbx.KFbxNode:
  value = currentNode.Translation.Get()
  print type(value), type(value[0]),value[0]
#<class 'fbx.fbxDouble3'> <type 'float'> 0.0
  value = currentNode.GetPreRotation(0)
  print type(value), value, value[0]
#<class 'fbx.KFbxVector4'> fbx.KFbxVector4(0.000000, 0.000000, 0.000000, 1.000000) 0.0

  • The bright and dark sides

You can open the scenes quickly, automatically.
You can safely open/close a lot of files like this.

I encountered some issues while saving cleaned file, so be sure to increment and not overwrite (as usual of course!)
You cannot blast, cannot plot, etc. ; well basically, you are not in mobu, nor using pyfbsdk module, but you can go very far (edit keys for example)

In my present experience with MotionBuilder, I used FBX SDK to:

- Scan all characters assets to parse a specific PreRotation joint value.
- Scan all scenes to list their content, sync it with asset management system.
- Done some stats about the artists worked, draw dependencies graph and find obsolete assets.

notice
Comments (3) Trackbacks (0)
  1. Thanks for sharing!

  2. Thanks very much.

    This all sounds very cool. 🙂

  3. Great stuff, thx for sharing!


Leave a comment

No trackbacks yet.

podcast
search
feedback