diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2015-03-24 18:29:23 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2015-03-24 18:29:23 +0300 |
commit | 1f43f9076360103027d40f2a62a22621ffa50351 (patch) | |
tree | 8ada6c92ea71fb82be09831e4b3c9b09f4e4e29d /io_scene_fbx | |
parent | 812130fd0b0a54df16f233e78af176868e8deae6 (diff) |
Fix T41719: UE4 - Blender FBX Export to Unreal Engine 4 Bone Translation Error.
Well, not exactly a fix, since the buggy behavior from FBXSDK side makes no sense to me.
So it's rather a hack to make that stupid piece of junk happy - now you can (optionally,
but ON by default) force exporting anim keys for all bones of an armature.
Should be safe for 2.74, just adds a new option, cannot see how it could break existing stuff.
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 | 16 | ||||
-rw-r--r-- | io_scene_fbx/fbx_utils.py | 19 |
3 files changed, 29 insertions, 14 deletions
diff --git a/io_scene_fbx/__init__.py b/io_scene_fbx/__init__.py index 85c8be0a..46fa90da 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, 2, 1), + "version": (3, 2, 2), "blender": (2, 74, 0), "location": "File > Import-Export", "description": "FBX IO meshes, UV's, vertex colors, materials, " @@ -331,6 +331,11 @@ class ExportFBX(bpy.types.Operator, ExportHelper, IOFBXOrientationHelper): description="Export baked keyframe animation", default=True, ) + bake_anim_use_all_bones = BoolProperty( + name="Key All Bones", + description="Force exporting at least one key of animation for all bones (needed with some target apps, like UE4)", + default=True, + ) bake_anim_use_nla_strips = BoolProperty( name="NLA Strips", description="Export each non-muted NLA strip as a separated FBX's AnimStack, if any, " @@ -439,6 +444,7 @@ class ExportFBX(bpy.types.Operator, ExportHelper, IOFBXOrientationHelper): layout.prop(self, "bake_anim") col = layout.column() col.enabled = self.bake_anim + 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_step") diff --git a/io_scene_fbx/export_fbx_bin.py b/io_scene_fbx/export_fbx_bin.py index d17d7145..57fc4de1 100644 --- a/io_scene_fbx/export_fbx_bin.py +++ b/io_scene_fbx/export_fbx_bin.py @@ -1823,6 +1823,7 @@ def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=No bake_step = scene_data.settings.bake_anim_step scene = scene_data.scene meshes = scene_data.data_meshes + force_keying = scene_data.settings.bake_anim_use_all_bones if objects is not None: # Add bones and duplis! @@ -1840,9 +1841,12 @@ def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=No objects = scene_data.objects back_currframe = scene.frame_current - animdata_ob = OrderedDict((ob_obj, (AnimationCurveNodeWrapper(ob_obj.key, 'LCL_TRANSLATION', (0.0, 0.0, 0.0)), - AnimationCurveNodeWrapper(ob_obj.key, 'LCL_ROTATION', (0.0, 0.0, 0.0)), - AnimationCurveNodeWrapper(ob_obj.key, 'LCL_SCALING', (1.0, 1.0, 1.0)))) + animdata_ob = OrderedDict((ob_obj, (AnimationCurveNodeWrapper(ob_obj.key, 'LCL_TRANSLATION', + ob_obj.is_bone and force_keying, (0.0, 0.0, 0.0)), + AnimationCurveNodeWrapper(ob_obj.key, 'LCL_ROTATION', + ob_obj.is_bone and force_keying, (0.0, 0.0, 0.0)), + AnimationCurveNodeWrapper(ob_obj.key, 'LCL_SCALING', + ob_obj.is_bone and force_keying, (1.0, 1.0, 1.0)))) for ob_obj in objects) animdata_shapes = OrderedDict() @@ -1851,7 +1855,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', (0.0,)) + acnode = AnimationCurveNodeWrapper(channel_key, 'SHAPE_KEY', False, (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) @@ -2724,6 +2728,7 @@ def save_single(operator, scene, filepath="", mesh_smooth_type='FACE', use_armature_deform_only=False, bake_anim=True, + bake_anim_use_all_bones=True, bake_anim_use_nla_strips=True, bake_anim_use_all_actions=True, bake_anim_step=1.0, @@ -2793,7 +2798,8 @@ def save_single(operator, scene, filepath="", context_objects, object_types, use_mesh_modifiers, 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_nla_strips, bake_anim_use_all_actions, bake_anim_step, bake_anim_simplify_factor, + bake_anim, bake_anim_use_all_bones, bake_anim_use_nla_strips, bake_anim_use_all_actions, + bake_anim_step, bake_anim_simplify_factor, False, media_settings, use_custom_props, ) diff --git a/io_scene_fbx/fbx_utils.py b/io_scene_fbx/fbx_utils.py index 38cf7e4d..07e4d824 100644 --- a/io_scene_fbx/fbx_utils.py +++ b/io_scene_fbx/fbx_utils.py @@ -651,7 +651,7 @@ 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') + __slots__ = ('elem_keys', '_keys', 'default_values', 'fbx_group', 'fbx_gname', 'fbx_props', 'force_keying') kinds = { 'LCL_TRANSLATION': ("Lcl Translation", "T", ("X", "Y", "Z")), @@ -660,16 +660,13 @@ class AnimationCurveNodeWrapper: 'SHAPE_KEY': ("DeformPercent", "DeformPercent", ("DeformPercent",)), } - def __init__(self, elem_key, kind, default_values=...): - """ - bdata might be an Object, DupliObject, Bone or PoseBone. - If Bone or PoseBone, armature Object must be provided. - """ + def __init__(self, elem_key, kind, force_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._keys = [] # (frame, values, write_flags) if default_values is not ...: assert(len(default_values) == len(self.fbx_props[0])) @@ -749,7 +746,11 @@ class AnimationCurveNodeWrapper: # If we write nothing (action doing nothing) and are in 'force_keep' mode, we key everything! :P # See T41766. - if (force_keep and not self): + # Also, it seems some importers (e.g. UE4) do not handle correctly armatures where some bones + # are not animated, but are children of animated ones, so added an option to systematically force writing + # one key in this case. + # See T41719, T41605, T41254... + if self.force_keying or (force_keep and not self): are_keyed[:] = [True] * len(are_keyed) # If we did key something, ensure first and last sampled values are keyed as well. @@ -768,6 +769,7 @@ class AnimationCurveNodeWrapper: if wrt: curve.append((currframe, val)) + force_keep = force_keep or self.force_keying for elem_key, fbx_group, fbx_gname, fbx_props in \ zip(self.elem_keys, self.fbx_group, self.fbx_gname, self.fbx_props): group_key = get_blender_anim_curve_node_key(scene, ref_id, elem_key, fbx_group) @@ -1129,7 +1131,8 @@ FBXExportSettings = namedtuple("FBXExportSettings", ( "context_objects", "object_types", "use_mesh_modifiers", "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_nla_strips", "bake_anim_use_all_actions", "bake_anim_step", "bake_anim_simplify_factor", + "bake_anim", "bake_anim_use_all_bones", "bake_anim_use_nla_strips", "bake_anim_use_all_actions", + "bake_anim_step", "bake_anim_simplify_factor", "use_metadata", "media_settings", "use_custom_props", )) |