Advertisement
Guest User

Blender Animation Export for UE4 / Unity

a guest
Jul 26th, 2016
165
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.31 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 (for this purpose, this script creates a simple skinned
  30. #   5 vertex pyramid on the fly that it exports - if you see a pyramid
  31. #   in your FBX file, everything is working correctly!)
  32. #  
  33. # Usage:
  34. #   Invoke Blender like this:
  35. #
  36. #   blender master.blend --python animation-export.py -- \
  37. #           animations.blend wildcard* target.fbx
  38. #
  39. #   - The first argument (master.blend) is the .blend file containing
  40. #     your character without animations
  41. #
  42. #   - The second argument (--python animation-export.py) runs this script
  43. #
  44. #   - The third argument (--) is a separator behind which the script
  45. #     arguments begin. You can add other Blender arguments before this.
  46. #
  47. #   - The fourth argument (animations.blend) specifies the .blend file
  48. #     containing the animation tracks you wish to export
  49. #
  50. #   - The fifth argument (wildcard*) is a wildcard string specifying
  51. #     which animations to append (this is useful if you have animations
  52. #     for multiple characters in animations.blend and want to append
  53. #     only the animations for the specific character you're exporting).
  54. #
  55. #   - The sixth argument (target.fbx) is the output file into which
  56. #     the animations will be exported
  57. #
  58. # Conventions:
  59. #   If you have multiple Armatures in your .blend file (very common if you
  60. #   use Rigify and kept the metarig), turn off interaction on them to make
  61. #   this script ignore them. Interaction can be turned off by disabling the
  62. #   little mouse cursor-like symbol in the outliner.
  63. #
  64. import bpy
  65. import sys
  66. import fnmatch
  67. import os
  68.  
  69. def append_actions_from_file(path, wildcard):
  70.     """
  71.    Appends all actions from another .blend file that match a given wildcard
  72.    """
  73.     # https://www.blender.org/api/blender_python_api_2_77_0/bpy.types.BlendDataLibraries.html
  74.     with bpy.data.libraries.load(path) as (data_from, data_to):
  75.         data_to.actions = [name for name in data_from.actions if fnmatch.fnmatch(name, wildcard)]
  76.  
  77. def make_all_layers_visible():
  78.     """
  79.    Makes all layers in the scene visible
  80.    """
  81.     for i in range(len(bpy.context.scene.layers)):
  82.         bpy.context.scene.layers[i] = True
  83.  
  84. def clear_selection():
  85.     """
  86.    Unselects all selected objects in the scene
  87.    """
  88.     for ob in bpy.data.objects:
  89.         ob.select = False
  90.  
  91. def select_first_armature():
  92.     """
  93.    Selects the first object of type Armature found in the scene
  94.    """
  95.     for ob in bpy.data.objects:
  96.         if ob.type == 'ARMATURE':
  97.             if ob.hide_select == False:
  98.                 print("Selected Armature for exporting: " + ob.name)
  99.                 ob.select = True
  100.                 return ob
  101.  
  102. def create_and_select_dummy_mesh(armature):
  103.     """
  104.    Creates a dummy mesh that is parented to the specified armature
  105.    """
  106.     verts = [
  107.         (-1.0, -1.0, 0.0),
  108.         (+1.0, -1.0, 0.0),
  109.         (+1.0, +1.0, 0.0),
  110.         (-1.0, +1.0, 0.0),
  111.         (0.0, 0.0, +1.0)
  112.     ]
  113.     faces = [
  114.         (0, 1, 4),
  115.         (1, 2, 4),
  116.         (2, 3, 4),
  117.         (3, 0, 4),
  118.         (2, 1, 0),
  119.         (0, 3, 2)
  120.     ]
  121.     mesh_data = bpy.data.meshes.new("AnimationDummy.Mesh")
  122.     mesh_data.from_pydata(verts, [], faces)
  123.     mesh_data.update()
  124.    
  125.     obj = bpy.data.objects.new("AnimationDummy", mesh_data)
  126.     scene = bpy.context.scene
  127.     scene.objects.link(obj)
  128.    
  129.     # The object needs to be select to be exported
  130.     obj.select = True
  131.    
  132.     # Add the Armature modifier to the mesh
  133.     mod = obj.modifiers.new('Armature', 'ARMATURE')
  134.     mod.object = armature
  135.     mod.use_bone_envelopes = False
  136.     mod.use_vertex_groups = True
  137.    
  138.     # Create a vertex group matching the first bone of the Armature
  139.     # (assumption: an Armature with less than 1 bone is impossible)
  140.     # and assign all vertices of the mesh to this vertex group
  141.     firstbone = armature.pose.bones[0]
  142.     vgroup = obj.vertex_groups.new(firstbone.name)
  143.     vgroup.add([0, 1, 2, 3, 4], 1.0, 'REPLACE')
  144.  
  145. # ----------------------------------------------------------------------
  146.  
  147. print("animation-export.py running...")
  148.  
  149. cwd = os.getcwd()
  150. print("base path: " + cwd)
  151.  
  152. argv = sys.argv
  153. argv = argv[argv.index("--") + 1:]  # get all args after "--"
  154.  
  155. # Animation library (.blend file) we want to append from
  156. animlib = argv[0]
  157. animlib = os.path.join(cwd, animlib)
  158. print("animation library: " + animlib)
  159.  
  160. # Wildcard of the actions we need to append
  161. wildcard = argv[1]
  162. print("actions to export: " + wildcard)
  163.  
  164. # Target path
  165. fbxpath = argv[2]
  166. print("fbx target path: " + fbxpath)
  167.  
  168. # Append the actions from the animation library
  169. append_actions_from_file(animlib, wildcard)
  170.  
  171. # Select the first Armature and the export dummy mesh in the scene
  172. make_all_layers_visible() # dummy objects might be on different layers
  173. clear_selection() # don't rely on what was selected when the user saved
  174. armature = select_first_armature() # we want to export the Armature
  175. create_and_select_dummy_mesh(armature)
  176.  
  177. # Export to FBX
  178. bpy.ops.export_scene.fbx(
  179.     filepath=fbxpath,
  180.     check_existing=False,
  181.     axis_forward='-Z',
  182.     axis_up='Y',
  183.     version='BIN7400',
  184.     use_selection=True,
  185.     global_scale=1.0,
  186.     apply_unit_scale=False,
  187.     bake_space_transform=False,
  188.     object_types={'ARMATURE', 'EMPTY', 'MESH'},
  189.     use_mesh_modifiers=True,
  190.     mesh_smooth_type='OFF',
  191.     use_mesh_edges=False,
  192.     use_tspace=True,
  193.     use_custom_props=False,
  194.     add_leaf_bones=False,
  195.     primary_bone_axis='Y',
  196.     secondary_bone_axis='X',
  197.     use_armature_deform_only=True,
  198.     bake_anim=True,
  199.     bake_anim_use_all_bones=True,
  200.     bake_anim_use_nla_strips=False,
  201.     bake_anim_use_all_actions=True,
  202.     bake_anim_force_startend_keying=True,
  203.     bake_anim_step=1.0,
  204.     bake_anim_simplify_factor=0.0,
  205.     use_anim=True,
  206.     use_anim_action_all=True,
  207.     use_default_take=False,
  208.     use_anim_optimize=False,
  209.     path_mode='AUTO',
  210.     embed_textures=False,
  211.     batch_mode='OFF',
  212.     use_metadata=True
  213. )
  214.  
  215. # Quit. We do not want to risk keeping the window open,
  216. # which might end up making the user save our patchwork file
  217. #
  218. quit()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement