[Bf-extensions-cvs] [1f43f90] master: Fix T41719: UE4 - Blender FBX Export to Unreal Engine 4 Bone Translation Error.

Bastien Montagne noreply at git.blender.org
Tue Mar 24 16:31:55 CET 2015


Commit: 1f43f9076360103027d40f2a62a22621ffa50351
Author: Bastien Montagne
Date:   Tue Mar 24 16:29:23 2015 +0100
Branches: master
https://developer.blender.org/rBA1f43f9076360103027d40f2a62a22621ffa50351

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.

===================================================================

M	io_scene_fbx/__init__.py
M	io_scene_fbx/export_fbx_bin.py
M	io_scene_fbx/fbx_utils.py

===================================================================

diff --git a/io_scene_fbx/__init__.py b/io_scene_fbx/__init__.py
index 85c8be0..46fa90d 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 d17d714..57fc4de 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 38cf7e4..07e4d82 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",
 ))



More information about the Bf-extensions-cvs mailing list