Advertisement
Guest User

Export Blender Animations to FBX from Linked Proxy-Armature

a guest
May 3rd, 2016
286
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.46 KB | None | 0 0
  1. # animation-export.py
  2. #
  3. # Purpose:
  4. #   When dealing with larger animation projects such as characters for
  5. #   video games or machinima, a lot of Actions (Blender animation clips)
  6. #   will result. It is advantageous to store these in separate files.
  7. #  
  8. #   Blender supports this scenario by allowing .blend files to "link"
  9. #   in objects from each other. However, as of now, the FBX exporter
  10. #   will not correctly export animation tracks in separate .blend files.
  11. #
  12. #   up to 2.72:   works if not using a proxy for the armature
  13. #   2.73:         nothing works at all
  14. #   2.74 to 2.77: only works with proxy but animations are detached
  15. #   2.78:         only works with proxy, animations attached to wrong object
  16. #
  17. #   In short, until the rewrite of the proxy system (may happen in 2.8),
  18. #   exporting animations on linked Armatures only works in Blender 2.72
  19. #   and without proxies, but the old FBX exporter has its own problems.
  20. #
  21. #   The only viable solution, then, is to:
  22. #     1) open the master file
  23. #     2) append all animation tracks from a separate .blend file to it
  24. #     3) export the master file
  25. #     4) exit without saving
  26. #
  27. #   This script will do just that. Since exporting the master meshes
  28. #   multiple times would be a giant waste of space, it only exports
  29. #   a single mesh (the mesh must be a part of the Armature, though).
  30. #  
  31. # Usage:
  32. #   Invoke Blender like this:
  33. #
  34. #   blender master.blend --python animation-export.py -- \
  35. #           animations.blend wildcard* target.fbx
  36. #
  37. #   - The first argument (master.blend) is the .blend file containing
  38. #     your character without animations
  39. #
  40. #   - The second argument (--python animation-export.py) runs this script
  41. #
  42. #   - The third argument (--) is a separator behind which the script
  43. #     arguments begin. You can add other Blender arguments before this.
  44. #
  45. #   - The fourth argument (animations.blend) specifies the .blend file
  46. #     containing the animation tracks you wish to export
  47. #
  48. #   - The fifth argument (wildcard*) is a wildcard string specifying
  49. #     which animations to append (this is useful if you have animations
  50. #     for multiple characters in animations.blend and want to append
  51. #     only the animations for the specific character you're exporting).
  52. #
  53. #   - The sixth argument (target.fbx) is the output file into which
  54. #     the animations will be exported
  55. #
  56. # Conventions:
  57. #   If you have multiple Armatures in your .blend file (very common if you
  58. #   use Rigify and kept the metarig), turn off interaction on them to make
  59. #   this script ignore them. Interaction can be turned off by disabling the
  60. #   little mouse cursor-like symbol in the outliner.
  61. #
  62. #   Blender's FBX exporter requires one rigged mesh to be exported with
  63. #   the Armature or animations won't work. By convention, this mesh needs
  64. #   to have a name ending in 'Dummy' or 'Plane' (you can change this
  65. #   convention near the bottom of the script).
  66. #
  67. import bpy
  68. import sys
  69. import fnmatch
  70. import os
  71.  
  72. def append_actions_from_file(path, wildcard):
  73.     """
  74.    Builds a list of the actions present in a blend file
  75.    """
  76.     # https://www.blender.org/api/blender_python_api_2_77_0/bpy.types.BlendDataLibraries.html
  77.     with bpy.data.libraries.load(path) as (data_from, data_to):
  78.         data_to.actions = [name for name in data_from.actions if fnmatch.fnmatch(name, wildcard)]
  79.  
  80. def clear_selection():
  81.     """
  82.    Unselects all selected objects in the scene
  83.    """
  84.     for ob in bpy.data.objects:
  85.         ob.select = False
  86.  
  87. def select_first_armature():
  88.     """
  89.    Selects the first object of type Armature found in the scene
  90.    """
  91.     for ob in bpy.data.objects:
  92.         if ob.type == 'ARMATURE':
  93.             if ob.hide_select == False:
  94.                 print("Selected Armature for exporting: " + ob.name)
  95.                 ob.select = True
  96.  
  97. def select_mesh_by_wildcard(wildcard):
  98.     """
  99.    Selects any objects matching a wildcard
  100.    """
  101.     for ob in bpy.data.objects:
  102.         if fnmatch.fnmatch(ob.name, wildcard):
  103.             print("Selected mesh for exporting: " + ob.name)
  104.             ob.select = True
  105.  
  106. def make_all_layers_visible():
  107.     """
  108.    Makes all layers in the scene visible
  109.    """
  110.     for i in range(len(bpy.context.scene.layers)):
  111.         bpy.context.scene.layers[i] = True
  112.  
  113. # ----------------------------------------------------------------------
  114.  
  115. print("animation-export.py running...")
  116.  
  117. cwd = os.getcwd()
  118. print("base path: " + cwd)
  119.  
  120. argv = sys.argv
  121. argv = argv[argv.index("--") + 1:]  # get all args after "--"
  122.  
  123. # Animation library (.blend file) we want to append from
  124. animlib = argv[0]
  125. animlib = os.path.join(cwd, animlib)
  126. print("animation library: " + animlib)
  127.  
  128. # Wildcard of the actions we need to append
  129. wildcard = argv[1]
  130. print("actions to export: " + wildcard)
  131.  
  132. # Target path
  133. fbxpath = argv[2]
  134. print("fbx target path: " + fbxpath)
  135.  
  136. # Append the actions
  137. append_actions_from_file(animlib, wildcard)
  138.  
  139. # Select the first Armature and the export dummy mesh in the scene
  140. make_all_layers_visible() # dummy objects might be on different layers
  141. clear_selection() # don't rely on what was selected when the user saved
  142. select_first_armature() # we want to export the Armature
  143. select_mesh_by_wildcard("*Plane") # FBX exporter needs at least one rigged mesh
  144. select_mesh_by_wildcard("*Dummy") # FBX exporter needs at least one rigged mesh
  145.  
  146. # Export to FBX
  147. bpy.ops.export_scene.fbx(
  148.     filepath=fbxpath,
  149.     check_existing=False,
  150.     axis_forward='-Z',
  151.     axis_up='Y',
  152.     version='BIN7400',
  153.     use_selection=True,
  154.     global_scale=1.0,
  155.     apply_unit_scale=False,
  156.     bake_space_transform=False,
  157.     object_types={'ARMATURE', 'EMPTY', 'MESH'},
  158.     use_mesh_modifiers=True,
  159.     mesh_smooth_type='OFF',
  160.     use_mesh_edges=False,
  161.     use_tspace=True,
  162.     use_custom_props=False,
  163.     add_leaf_bones=False,
  164.     primary_bone_axis='Y',
  165.     secondary_bone_axis='X',
  166.     use_armature_deform_only=True,
  167.     bake_anim=True,
  168.     bake_anim_use_all_bones=True,
  169.     bake_anim_use_nla_strips=False,
  170.     bake_anim_use_all_actions=True,
  171.     bake_anim_force_startend_keying=True,
  172.     bake_anim_step=1.0,
  173.     bake_anim_simplify_factor=0.0,
  174.     use_anim=True,
  175.     use_anim_action_all=True,
  176.     use_default_take=False,
  177.     use_anim_optimize=False,
  178.     path_mode='AUTO',
  179.     embed_textures=False,
  180.     batch_mode='OFF',
  181.     use_metadata=True
  182. )
  183.  
  184. # Quit. We do not want to risk keeping the window open,
  185. # which might end up making the user save our patchwork file
  186. #
  187. quit()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement