Categories
Blog Post rigtip tutorial

Guest Post : FBX file solutions with Python FBX SDK

FBX, love it or hate it, it has continued to be used and integrated into many game engines and software packages.

We bring you another guest post to help you gain control over and improve the use of FBX in your pipeline.

And now Randall Hess, Principal Technical Animator at Boss Key Productions.

 

 

FBX issues and such

I’ve recently given some scripting assistance, to a technical animator friend of mine at another game studio, that I feel not many folks are familiar with. He was having issues losing attributes or properties when exporting from Motionbuilder to FBX. This is not an uncommon problem with FBX and depending on which version of Maya, 3dsmax or Motionbuilder you are running, the differences with attributes/properties changing or getting completely lost, depending on the object they are associated with, can be very frustrating. I worked with the FBX team many years ago in an attempt to get these and other issues addressed. Some things were resolved but its not ideal to be black boxed by the plugin and its limitations when your pipeline depends on it. This is where the FBX SDK comes in. While Autodesk has not open sourced the fbx plugin, they do continually update the SDK for C++ and Python. With this SDK you can modify the fbx scene file that you are exporting or importing. I was introduced to FBX Python SDK by my friend Jason Parks, many years ago when we worked together at Volition and I have been leveraging its usefulness ever since.

 

Python FBX SDK Uses

Listed below are just a few things that you can modify in an FBX file with the SDK

  • Adding or removing properties/attributes
  • Removing Namespaces before importing or after exporting
  • Removing objects that were not a part of the specifically selected objects but were associated
  • Removing textures or renaming paths
  • Rename objects in fbx scenes without having to re-export the file from the source
  • You can modify most anything in an FBX scene, external from a DCC application

 

Setting up the Python FBX SDK

http://www.autodesk.com/products/fbx/overview
Hit the “Get FBX SDK” link and on the next page look for Python Binding. Choose your flavor, Windows, Linux, or Mac, download and install/extract the package. If you need an earlier version for compatibility reasons go to the “SDK Archive” link. I’m still using 2014.1 and it works fine with Maya 2014/2015/2016 and UnrealEngine 4.x.

You will need to install the package you have chosen to download. This package has a lot of incredibly useful samples for getting started with FBX in python and getting an understanding of the FBX scene in general. If you are at all familiar working with Python in Motionbuilder, pyfbxsdk, it is almost exactly the same and this should be quite easy to pick up.

 

Installing for Maya

If you are working in the latest versions of Maya 2014 and higher you will want the files in lib/Python27_x64 or x86. There are three main files that you will want to point to or add to your existing python paths for Maya.

Here is a snippet to add to a script or your startup for Maya.

import sys
sys.path.append(r'/FBXPath')

These are the files that are needed:
fbx.pyd
FbxCommon.py
fbxsip.pyd

Here is some startup code for the FBX Scene Wrapper Class.

 

import fbx
import FbxCommon

class FBX_Class(object):
 
 def __init__(self, filename):
  """
  FBX Scene Object
  """
  self.filename = filename  
  self.scene = None
  self.sdk_manager = None
  self.sdk_manager, self.scene = FbxCommon.InitializeSdkObjects()
  FbxCommon.LoadScene(self.sdk_manager, self.scene, filename)
  
  self.root_node = self.scene.GetRootNode()
  self.scene_nodes = self.get_scene_nodes()

fbx_scene = FBX_Class(r'c:\my_path\character.fbx') # instantiate the class


The main thing to be aware of with most classes, is that you have to instantiate them to access their internal methods. Here we need to pass an argument that is a string of the fbx file path and name. The _init_ method will automatically parse and load the fbx scene. The one thing when parsing a file that you care about is speed, luckily when working with the Fbx SDK, even in python, I find it to be incredibly fast even on large Fbx files.

Now that the fbx scene is loaded we can go nuts changing the fbx file however we want. At Boss Key, after exporting I run a post process to modify all the fbx files, be it a character skeletal mesh, a weapon, or an animation file. I remove namespaces, empty display layers, remove objects that are in exported hierarchies that I don’t want importing into UE4, or cleaning up any properties when necessary.

import FBX_Scene

def clean_character_scene(fbx_file):
 """
 Clean up character fbx file
 """
 
 # open the fbx scenes and get the scene nodes
 fbx_scene = FBX_Class(fbx_file)
 if not fbx_scene:
  return False

 remove_names = []
 keep_names = []

 # remove invalid nodes noted by properties assigned in the DCC application
 all_nodes = fbx_scene.get_scene_nodes()
 for node in all_nodes:  
  export_property = fbx_scene.get_property(node, 'no_export')
  if export_property:
   property_value = fbx_scene.get_property_value(node, 'no_export')
   if property_value == True:    
    node_name = node.GetName()
    fbx_scene.scene.DisconnectSrcObject(node)     
    remove_names.append(node_name)
   else:
    node_name = node.GetName()
    keep_names.append(node_name)

 # remove the nodes from the scene by name 
 fbx_scene.remove_nodes_by_names(remove_names)

 # remove display layers
 # For some reason these change FbxCollection ID and NodeName
 layer_objs = fbx_scene.get_class_nodes(fbx.FbxCollectionExclusive.ClassId)
 if layer_objs:
  remove_layers(fbx_scene, layer_objs)
  
 # remove FbxContainers
 nodes = fbx_scene.get_class_nodes(fbx.FbxObject.ClassId)
 if nodes in nodes:
   if node.GetClassId().GetName() == 'FbxContainer':   
    # disconnect the layer from the scene
    node.DisconnectAllDstObject()
    node.DisconnectAllSrcObject()
    fbx_scene.scene.RootProperty.DisconnectSrcObject(node)

 # remove display layers
 display_layers = fbx_scene.get_type_objects(u'DisplayLayer') 
 if display_layers:  
  remove_layers(fbx_scene, display_layers)

 # save the modified fbx scene
 fbx_scene.save()
 
 return True

Right after I run my custom fbx export method in Maya I will call a method, such as the one above, all in the same process. So when the artist is finished exporting they won’t even know I opened up the fbx and modified it for the better.

The great thing about the FBX Python SDK is that you don’t need a DCC application to run it. You can run standalone processes and modify all of your mocap or skeletal mesh files, renaming nodes, changing hierarchies or adding properties, all without having to return to the original DCC to reexport. Once you start working with the Fbx Python SDK you may never stop.

The Python SDK can process importing mocap before you actually import it into your scene and remove namespace issues.

 

Once I got familiar enough with FBX SDK I started a project which became the Saints Row Mod Tools. I wrote the tool that converted fbx scenes into the file formats needed for Saints Row 3, and Saints Row IV for for modding purposes. Before we used custom plugins, tools and processes that would be far too complex to release to the community and support for multiple DCCs. Fbx covers all the bases so this was a worthwhile tool and the community seemed to appreciate it.  If you want to download the python script that really digs into breaking down the fbx scene, feel free to hop over to the saintsrowmods forums and grab it.

 

My Public Gists (full examples from this post)
https://gist.github.com/Meatplowz

 

On a side note if you want to actually extend the plugins with C++ you can do so.
FBX SDK Plugin Extension

 

Let me know if you have any questions on the Fbx Python SDK. If you have any suggestions or tips yourself please share them as well.

6 replies on “Guest Post : FBX file solutions with Python FBX SDK”

Hi Adam,
The article is great!
But I am having some other issue related to FBX conversion.
I want to save mediapipe face mesh 468 landmarks to fbx file.
May be ply file to obj and obj to fbx , I tried with multiple way but for every library to convert into fbx I need to install libraries like bpy, fbx, pyfbx, fbx-sdk but all libraries are having support to below python 3.7 version and I want to stick with 3.8 or 3.9 .
Please guide me.

Hi Adam, thanks for the writeup!

I was wondering if you were familiar with a way to clip fbx ranges in the actual export (as opposed to creating clip ‘takes’ as described in other articles online, ie. defTechAndrew/fbx_animation_editing.py)

I’ve been scouring the web and haven’t found anything about what I would’ve expected to be quite a simple thing to do.

Hey Adam,
I would say convenience would be the point. Sure you can save a version of your scene off and that works fine, you may also have a bit more control in that method. If your scene is heavy, then you have to pay the cost of the longer save, and then the longer reload to get back to the prior state. Additionally, the python FBX SDK allows you to modify files external from Maya and prior to importing. With that you can batch change names, connection or texture paths in fbx files if necessary without even opening Maya. So many things can be done but it all depends on your needs. It’s best to have as much flexibility as possible.

Great post! Ill bookmark this for later, currently we have a Maya only pipeline and I have scripts setup to save a copy of the scene and remove everything we don’t want before it exports.

Sounds like this was for a much more complicated pipeline, but at what point would you say would be good to transition to direct FBX editing?

Leave a Reply

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.