浏览代码

Merge pull request #71 from Jason0214/fix_remove_empty_active_action

Fix remove active action when it is None
sdfgeoff 7 年之前
父节点
当前提交
22dca94a9a

+ 75 - 60
io_scene_godot/converters/animation.py

@@ -160,8 +160,13 @@ class AnimationPlayer(NodeTemplate):
     def create_animation_resource(self, escn_file, action):
         """Create a new animation resource and add it into escn file"""
         new_anim_resource = AnimationResource()
-        resource_id = escn_file.add_internal_resource(
-            new_anim_resource, action)
+
+        # add animation resource without checking hash,
+        # blender action is in world space, while godot animation
+        # is in local space (parent space),  so identical actions
+        # are not necessarily generates identical godot animations
+        resource_id = escn_file.force_add_internal_resource(new_anim_resource)
+
         self['anims/{}'.format(action.name)] = (
             "SubResource({})".format(resource_id))
 
@@ -735,23 +740,28 @@ def export_animation_data(escn_file, export_settings, godot_node,
     has_pose_cst = has_pose_constraint(blender_object)
     need_bake = action_type == 'transform' and (has_obj_cst or has_pose_cst)
 
+    if blender_object.animation_data is None and not need_bake:
+        return
+
     def action_baker(action_to_bake):
         """A quick call to bake OBJECT and POSE action"""
         # note it used variable outside its scope
-        if has_obj_cst:
-            action_baked = bake_constraint_to_action(
-                blender_object, action_to_bake, "OBJECT", False)
-        if has_pose_cst:
-            if has_obj_cst:
-                action_baked = bake_constraint_to_action(
-                    blender_object, action_baked, "POSE", True)
-            else:
-                action_baked = bake_constraint_to_action(
-                    blender_object, action_to_bake, "POSE", False)
-        return action_baked
-
-    if blender_object.animation_data is None and not need_bake:
-        return
+        if has_obj_cst and has_pose_cst:
+            tmp = bake_constraint_to_action(
+                blender_object, action_to_bake, "OBJECT", False
+            )
+            ret = bake_constraint_to_action(
+                blender_object, tmp, "POSE", True
+            )
+        elif has_pose_cst:
+            ret = bake_constraint_to_action(
+                blender_object, action_to_bake, "POSE", False
+            )
+        elif has_obj_cst:
+            ret = bake_constraint_to_action(
+                blender_object, action_to_bake, "POSE", False
+            )
+        return ret
 
     animation_player = get_animation_player(
         escn_file, export_settings, godot_node
@@ -762,68 +772,73 @@ def export_animation_data(escn_file, export_settings, godot_node,
 
     # back up active action to reset back after finish exporting
     if blender_object.animation_data:
-        active_action_backup = blender_object.animation_data.action
+        active_action = blender_object.animation_data.action
     else:
-        active_action_backup = None
+        active_action = None
 
-    # ---- export active action
-    action_active = active_action_backup
-    if (action_active is not None or
-            not blender_object.animation_data and need_bake):
+    def export_active_action(active_action):
+        """Export the active action, if needed would call bake,
+        note that active_action maybe None, which means the object
+        has constraint and need to bake to action"""
         if need_bake:
-            if action_active is not None:
-                action_active.name = action_active.name + BAKING_SUFFIX
-                exported_actions.add(action_active)
-            action_active = action_baker(action_active)
+            if active_action is not None:
+                active_action.name = active_action.name + BAKING_SUFFIX
+                exported_actions.add(active_action)
+            action_active_to_export = action_baker(active_action)
+        else:
+            action_active_to_export = active_action
 
-        # must be put after active action being baked, because action_active
-        # may be None before baking
         if animation_player.default_animation is None:
             animation_player.add_default_animation_resource(
-                escn_file, action_active
+                escn_file, action_active_to_export
             )
-        # export active action
-        exporter_func(godot_node, animation_player, blender_object,
-                      action_active, animation_player.default_animation)
-
-    # ---- export actions in nla tracks
-    def export_action(action_to_export):
-        """Export an action, would call baking if needed"""
-        if (action_to_export is None or
-                action_to_export in exported_actions):
-            return
-
-        exported_actions.add(action_to_export)
-        # backup as it may overwrite by baking
-        action_to_export_backup = action_to_export
+
+        exporter_func(
+            godot_node, animation_player, blender_object,
+            action_active_to_export, animation_player.default_animation
+        )
+
         if need_bake:
-            # action_to_export is new created, need to be removed later
-            action_to_export.name = action_to_export.name + BAKING_SUFFIX
-            action_to_export = action_baker(action_to_export)
+            # remove new created action
+            bpy.data.actions.remove(action_active_to_export)
+            if active_action is not None:
+                # set back active action name
+                active_action.name = active_action.name[:-len(BAKING_SUFFIX)]
+
+    if (active_action is not None or
+            not blender_object.animation_data and need_bake):
+        export_active_action(active_action)
+
+    def export_nla_action(nla_action):
+        """Export an action in nla_tracks, would call baking if needed"""
+        exported_actions.add(nla_action)
+        if need_bake:
+            nla_action.name = nla_action.name + BAKING_SUFFIX
+            # nla_action_to_export is new created, need to be removed later
+            nla_action_to_export = action_baker(nla_action)
+        else:
+            nla_action_to_export = nla_action
 
         anim_resource = animation_player.create_animation_resource(
-            escn_file, action_to_export
+            escn_file, nla_action_to_export
         )
 
         exporter_func(godot_node, animation_player, blender_object,
-                      action_to_export, anim_resource)
+                      nla_action_to_export, anim_resource)
 
         if need_bake:
             # remove baked action
-            action_to_export_backup.name = action_to_export_backup.name[
-                :-len(BAKING_SUFFIX)]
-            bpy.data.actions.remove(action_to_export)
+            bpy.data.actions.remove(nla_action_to_export)
+            nla_action.name = nla_action.name[:-len(BAKING_SUFFIX)]
 
     # export actions in nla_tracks, each exported to seperate
     # animation resources
     for nla_track in blender_object.animation_data.nla_tracks:
         for nla_strip in nla_track.strips:
-            # make sure no duplicate action exported
-            export_action(nla_strip.action)
-
-    if need_bake:
-        if active_action_backup is not None:
-            blender_object.animation_data.action = active_action_backup
-            active_action_backup.name = action_active.name[
-                :-len(BAKING_SUFFIX)]
-        bpy.data.actions.remove(action_active)
+            # here make sure no duplicate action exported
+            if (nla_strip.action is not None and
+                    nla_strip.action not in exported_actions):
+                export_nla_action(nla_strip.action)
+
+    if active_action is not None:
+        blender_object.animation_data.action = active_action

+ 8 - 1
io_scene_godot/structures.py

@@ -67,10 +67,17 @@ class ESCNFile:
         """See comment on external resources. It's the same"""
         if self.get_internal_resource(hashable) is not None:
             raise Exception("Attempting to add object to file twice")
+        resource_id = self.force_add_internal_resource(item)
+        self._internal_hashes[hashable] = resource_id
+        return resource_id
+
+    def force_add_internal_resource(self, item):
+        """Add an internal resource without providing an hashable,
+        ATTENTION: it should not be called unless an hashable can not
+        be found"""
         self.internal_resources.append(item)
         index = len(self.internal_resources)
         item.heading['id'] = index
-        self._internal_hashes[hashable] = index
         return index
 
     def add_node(self, item):

文件差异内容过多而无法显示
+ 37 - 0
tests/reference_exports/action_animation/animation_shared_action.escn


文件差异内容过多而无法显示
+ 9 - 0
tests/reference_exports/action_animation/animation_with_nla_tracks.escn


二进制
tests/test_scenes/action_animation/animation_shared_action.blend


二进制
tests/test_scenes/action_animation/animation_with_nla_tracks.blend


部分文件因为文件数量过多而无法显示