diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2015-07-15 22:37:41 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2015-07-15 22:37:41 +0300 |
commit | b7567791a19f85b6886ab3bc933f9c2e1ed7333f (patch) | |
tree | a21a8a2c131bdd317dad5ecc3c1f763440342f89 /io_scene_fbx | |
parent | 3d0f53c1d65f3a55d108f25b1ee8f391ef323910 (diff) |
FBX export: add option to not key first/last frames of an exported action.
User request (see T45438).
Diffstat (limited to 'io_scene_fbx')
-rw-r--r-- | io_scene_fbx/__init__.py | 8 | ||||
-rw-r--r-- | io_scene_fbx/export_fbx_bin.py | 12 | ||||
-rw-r--r-- | io_scene_fbx/fbx_utils.py | 16 |
3 files changed, 24 insertions, 12 deletions
diff --git a/io_scene_fbx/__init__.py b/io_scene_fbx/__init__.py index da4a4233..7c752458 100644 --- a/io_scene_fbx/__init__.py +++ b/io_scene_fbx/__init__.py @@ -21,7 +21,7 @@ bl_info = { "name": "FBX format", "author": "Campbell Barton, Bastien Montagne, Jens Restemeier", - "version": (3, 4, 7), + "version": (3, 4, 8), "blender": (2, 74, 0), "location": "File > Import-Export", "description": "FBX IO meshes, UV's, vertex colors, materials, textures, cameras, lamps and actions", @@ -373,6 +373,11 @@ class ExportFBX(bpy.types.Operator, ExportHelper, IOFBXOrientationHelper): "others will get no animation at all)", default=True, ) + bake_anim_force_startend_keying = BoolProperty( + name="Force Start/End Keying", + description="Always add a keyframe at start and end of actions for animated channels", + default=True, + ) bake_anim_step = FloatProperty( name="Sampling Rate", description="How often to evaluate animated values (in frames)", @@ -475,6 +480,7 @@ class ExportFBX(bpy.types.Operator, ExportHelper, IOFBXOrientationHelper): col.prop(self, "bake_anim_use_all_bones") col.prop(self, "bake_anim_use_nla_strips") col.prop(self, "bake_anim_use_all_actions") + col.prop(self, "bake_anim_force_startend_keying") col.prop(self, "bake_anim_step") col.prop(self, "bake_anim_simplify_factor") else: diff --git a/io_scene_fbx/export_fbx_bin.py b/io_scene_fbx/export_fbx_bin.py index 1e6aa383..cfb57689 100644 --- a/io_scene_fbx/export_fbx_bin.py +++ b/io_scene_fbx/export_fbx_bin.py @@ -1850,6 +1850,7 @@ def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=No scene = scene_data.scene meshes = scene_data.data_meshes force_keying = scene_data.settings.bake_anim_use_all_bones + force_sek = scene_data.settings.bake_anim_force_startend_keying if objects is not None: # Add bones and duplis! @@ -1874,9 +1875,9 @@ def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=No ACNW = AnimationCurveNodeWrapper loc, rot, scale, _m, _mr = ob_obj.fbx_object_tx(scene_data) rot_deg = tuple(convert_rad_to_deg_iter(rot)) - animdata_ob[ob_obj] = (ACNW(ob_obj.key, 'LCL_TRANSLATION', ob_obj.is_bone and force_keying, loc), - ACNW(ob_obj.key, 'LCL_ROTATION', ob_obj.is_bone and force_keying, rot_deg), - ACNW(ob_obj.key, 'LCL_SCALING', ob_obj.is_bone and force_keying, scale)) + animdata_ob[ob_obj] = (ACNW(ob_obj.key, 'LCL_TRANSLATION', ob_obj.is_bone and force_keying, force_sek, loc), + ACNW(ob_obj.key, 'LCL_ROTATION', ob_obj.is_bone and force_keying, force_sek, rot_deg), + ACNW(ob_obj.key, 'LCL_SCALING', ob_obj.is_bone and force_keying, force_sek, scale)) p_rots[ob_obj] = rot animdata_shapes = OrderedDict() @@ -1885,7 +1886,7 @@ def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=No if not me.shape_keys.use_relative: continue for shape, (channel_key, geom_key, _shape_verts_co, _shape_verts_idx) in shapes.items(): - acnode = AnimationCurveNodeWrapper(channel_key, 'SHAPE_KEY', False, (0.0,)) + acnode = AnimationCurveNodeWrapper(channel_key, 'SHAPE_KEY', False, force_sek, (0.0,)) # Sooooo happy to have to twist again like a mad snake... Yes, we need to write those curves twice. :/ acnode.add_group(me_key, shape.name, shape.name, (shape.name,)) animdata_shapes[channel_key] = (acnode, me, shape) @@ -2817,6 +2818,7 @@ def save_single(operator, scene, filepath="", bake_anim_use_all_actions=True, bake_anim_step=1.0, bake_anim_simplify_factor=1.0, + bake_anim_force_startend_keying=True, add_leaf_bones=False, primary_bone_axis='Y', secondary_bone_axis='X', @@ -2881,7 +2883,7 @@ def save_single(operator, scene, filepath="", mesh_smooth_type, use_mesh_edges, use_tspace, use_armature_deform_only, add_leaf_bones, bone_correction_matrix, bone_correction_matrix_inv, bake_anim, bake_anim_use_all_bones, bake_anim_use_nla_strips, bake_anim_use_all_actions, - bake_anim_step, bake_anim_simplify_factor, + bake_anim_step, bake_anim_simplify_factor, bake_anim_force_startend_keying, False, media_settings, use_custom_props, ) diff --git a/io_scene_fbx/fbx_utils.py b/io_scene_fbx/fbx_utils.py index cb761dd3..c4ae3383 100644 --- a/io_scene_fbx/fbx_utils.py +++ b/io_scene_fbx/fbx_utils.py @@ -719,7 +719,9 @@ class AnimationCurveNodeWrapper: This class provides a same common interface for all (FBX-wise) AnimationCurveNode and AnimationCurve elements, and easy API to handle those. """ - __slots__ = ('elem_keys', '_keys', 'default_values', 'fbx_group', 'fbx_gname', 'fbx_props', 'force_keying') + __slots__ = ( + 'elem_keys', '_keys', 'default_values', 'fbx_group', 'fbx_gname', 'fbx_props', + 'force_keying', 'force_startend_keying') kinds = { 'LCL_TRANSLATION': ("Lcl Translation", "T", ("X", "Y", "Z")), @@ -728,13 +730,14 @@ class AnimationCurveNodeWrapper: 'SHAPE_KEY': ("DeformPercent", "DeformPercent", ("DeformPercent",)), } - def __init__(self, elem_key, kind, force_keying, default_values=...): + def __init__(self, elem_key, kind, force_keying, force_startend_keying, default_values=...): self.elem_keys = [elem_key] assert(kind in self.kinds) self.fbx_group = [self.kinds[kind][0]] self.fbx_gname = [self.kinds[kind][1]] self.fbx_props = [self.kinds[kind][2]] self.force_keying = force_keying + self.force_startend_keying = force_startend_keying self._keys = [] # (frame, values, write_flags) if default_values is not ...: assert(len(default_values) == len(self.fbx_props[0])) @@ -822,9 +825,10 @@ class AnimationCurveNodeWrapper: are_keyed[:] = [True] * len(are_keyed) # If we did key something, ensure first and last sampled values are keyed as well. - for idx, is_keyed in enumerate(are_keyed): - if is_keyed: - keys[0][2][idx] = keys[-1][2][idx] = True + if self.force_startend_keying: + for idx, is_keyed in enumerate(are_keyed): + if is_keyed: + keys[0][2][idx] = keys[-1][2][idx] = True def get_final_data(self, scene, ref_id, force_keep=False): """ @@ -1200,7 +1204,7 @@ FBXExportSettings = namedtuple("FBXExportSettings", ( "mesh_smooth_type", "use_mesh_edges", "use_tspace", "use_armature_deform_only", "add_leaf_bones", "bone_correction_matrix", "bone_correction_matrix_inv", "bake_anim", "bake_anim_use_all_bones", "bake_anim_use_nla_strips", "bake_anim_use_all_actions", - "bake_anim_step", "bake_anim_simplify_factor", + "bake_anim_step", "bake_anim_simplify_factor", "bake_anim_force_startend_keying", "use_metadata", "media_settings", "use_custom_props", )) |