Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # animation-export.py
- #
- # Purpose:
- # When dealing with larger animation projects such as characters for
- # video games or machinima, a lot of Actions (Blender animation clips)
- # will result. It is advantageous to store these in separate files.
- #
- # Blender supports this scenario by allowing .blend files to "link"
- # in objects from each other. However, as of now, the FBX exporter
- # will not correctly export animation tracks in separate .blend files.
- #
- # up to 2.72: works if not using a proxy for the armature
- # 2.73: nothing works at all
- # 2.74 to 2.77: only works with proxy but animations are detached
- # 2.78: only works with proxy, animations attached to wrong object
- #
- # In short, until the rewrite of the proxy system (may happen in 2.8),
- # exporting animations on linked Armatures only works in Blender 2.72
- # and without proxies, but the old FBX exporter has its own problems.
- #
- # The only viable solution, then, is to:
- # 1) open the master file
- # 2) append all animation tracks from a separate .blend file to it
- # 3) export the master file
- # 4) exit without saving
- #
- # This script will do just that. Since exporting the master meshes
- # multiple times would be a giant waste of space, it only exports
- # a single mesh (the mesh must be a part of the Armature, though).
- #
- # Usage:
- # Invoke Blender like this:
- #
- # blender master.blend --python animation-export.py -- \
- # animations.blend wildcard* target.fbx
- #
- # - The first argument (master.blend) is the .blend file containing
- # your character without animations
- #
- # - The second argument (--python animation-export.py) runs this script
- #
- # - The third argument (--) is a separator behind which the script
- # arguments begin. You can add other Blender arguments before this.
- #
- # - The fourth argument (animations.blend) specifies the .blend file
- # containing the animation tracks you wish to export
- #
- # - The fifth argument (wildcard*) is a wildcard string specifying
- # which animations to append (this is useful if you have animations
- # for multiple characters in animations.blend and want to append
- # only the animations for the specific character you're exporting).
- #
- # - The sixth argument (target.fbx) is the output file into which
- # the animations will be exported
- #
- # Conventions:
- # If you have multiple Armatures in your .blend file (very common if you
- # use Rigify and kept the metarig), turn off interaction on them to make
- # this script ignore them. Interaction can be turned off by disabling the
- # little mouse cursor-like symbol in the outliner.
- #
- import bpy
- import sys
- import fnmatch
- import os
- def append_actions_from_file(path, wildcard):
- """
- Builds a list of the actions present in a blend file
- """
- # https://www.blender.org/api/blender_python_api_2_77_0/bpy.types.BlendDataLibraries.html
- with bpy.data.libraries.load(path) as (data_from, data_to):
- data_to.actions = [name for name in data_from.actions if fnmatch.fnmatch(name, wildcard)]
- def make_all_layers_visible():
- """
- Makes all layers in the scene visible
- """
- for i in range(len(bpy.context.scene.layers)):
- bpy.context.scene.layers[i] = True
- def clear_selection():
- """
- Unselects all selected objects in the scene
- """
- for ob in bpy.data.objects:
- ob.select = False
- def select_first_armature():
- """
- Selects the first object of type Armature found in the scene
- """
- for ob in bpy.data.objects:
- if ob.type == 'ARMATURE':
- if ob.hide_select == False:
- print("Selected Armature for exporting: " + ob.name)
- ob.select = True
- return ob
- def create_and_select_dummy_mesh(armature):
- """
- Creates a dummy mesh that is parented to the specified armature
- """
- verts = [
- (-1.0, -1.0, 0.0),
- (+1.0, -1.0, 0.0),
- (+1.0, +1.0, 0.0),
- (-1.0, +1.0, 0.0),
- (0.0, 0.0, +1.0)
- ]
- faces = [
- (0, 1, 4),
- (1, 2, 4),
- (2, 3, 4),
- (3, 0, 4),
- (2, 1, 0),
- (0, 3, 2)
- ]
- mesh_data = bpy.data.meshes.new("AnimationDummy.Mesh")
- mesh_data.from_pydata(verts, [], faces)
- mesh_data.update()
- obj = bpy.data.objects.new("AnimationDummy", mesh_data)
- scene = bpy.context.scene
- scene.objects.link(obj)
- # The object needs to be select to be exported
- obj.select = True
- # Add the Armature modifier to the mesh
- mod = obj.modifiers.new('Armature', 'ARMATURE')
- mod.object = armature
- mod.use_bone_envelopes = False
- mod.use_vertex_groups = True
- # Create a vertex group matching the first bone of the Armature
- # (assumption: an Armature with less than 1 bone is impossible)
- # and assign all vertices of the mesh to this vertex group
- firstbone = armature.pose.bones[0]
- vgroup = obj.vertex_groups.new(firstbone.name)
- vgroup.add([0, 1, 2, 3, 4], 1.0, 'REPLACE')
- # ----------------------------------------------------------------------
- print("animation-export.py running...")
- cwd = os.getcwd()
- print("base path: " + cwd)
- argv = sys.argv
- argv = argv[argv.index("--") + 1:] # get all args after "--"
- # Animation library (.blend file) we want to append from
- animlib = argv[0]
- animlib = os.path.join(cwd, animlib)
- print("animation library: " + animlib)
- # Wildcard of the actions we need to append
- wildcard = argv[1]
- print("actions to export: " + wildcard)
- # Target path
- fbxpath = argv[2]
- print("fbx target path: " + fbxpath)
- # Append the actions from the animation library
- append_actions_from_file(animlib, wildcard)
- # Select the first Armature and the export dummy mesh in the scene
- make_all_layers_visible() # dummy objects might be on different layers
- clear_selection() # don't rely on what was selected when the user saved
- armature = select_first_armature() # we want to export the Armature
- create_and_select_dummy_mesh(armature)
- # Export to FBX
- bpy.ops.export_scene.fbx(
- filepath=fbxpath,
- check_existing=False,
- axis_forward='-Z',
- axis_up='Y',
- version='BIN7400',
- use_selection=True,
- global_scale=1.0,
- apply_unit_scale=False,
- bake_space_transform=False,
- object_types={'ARMATURE', 'EMPTY', 'MESH'},
- use_mesh_modifiers=True,
- mesh_smooth_type='OFF',
- use_mesh_edges=False,
- use_tspace=True,
- use_custom_props=False,
- add_leaf_bones=False,
- primary_bone_axis='Y',
- secondary_bone_axis='X',
- use_armature_deform_only=True,
- bake_anim=True,
- bake_anim_use_all_bones=True,
- bake_anim_use_nla_strips=False,
- bake_anim_use_all_actions=True,
- bake_anim_force_startend_keying=True,
- bake_anim_step=1.0,
- bake_anim_simplify_factor=0.0,
- use_anim=True,
- use_anim_action_all=True,
- use_default_take=False,
- use_anim_optimize=False,
- path_mode='AUTO',
- embed_textures=False,
- batch_mode='OFF',
- use_metadata=True
- )
- # Quit. We do not want to risk keeping the window open,
- # which might end up making the user save our patchwork file
- #
- quit()
Add Comment
Please, Sign In to add comment