Browse Source

Fix should obj exporting check, fix non-deform bone in constraint issue (#156)

* fix whether object should exported check

* fix constrained action with unexported bone

* use cached bone rest

* update test scene
Lu Jiacheng 6 years ago
parent
commit
fe6d206098

+ 49 - 25
io_scene_godot/converters/animation/action.py

@@ -102,11 +102,23 @@ def has_obj_fcurves(action_strip):
     return False
 
 
+# pylint: disable-msg=too-many-locals
 def export_constrained_xform_action(godot_node, animation_player,
                                     blender_object, action_strip,
                                     animation_resource):
     """Export transform animation of any object has constraints,
     it use frame_set to traversal each frame, so it's costly"""
+    def build_pbone_parent_map(godot_node, blender_object):
+        pose_bone_parent_map = dict()
+        for pbone in blender_object.pose.bones:
+            pbone_parent = pbone.parent
+            # find parent bone and ensure it is exported in godot node
+            while (pbone_parent is not None and
+                   godot_node.find_bone_id(pbone_parent.name) == -1):
+                pbone_parent = pbone_parent.parent
+            pose_bone_parent_map[pbone.name] = pbone_parent
+        return pose_bone_parent_map
+
     first_frame, last_frame = action_strip.frame_range
 
     obj_xform_mats = list()
@@ -114,19 +126,30 @@ def export_constrained_xform_action(godot_node, animation_player,
 
     scene = bpy.context.scene
     frame_backup = scene.frame_current
+
+    has_pbone_actions = (godot_node.get_type() == 'Skeleton' and
+                         blender_object.pose is not None)
+    if has_pbone_actions:
+        pbone_parent_map = build_pbone_parent_map(godot_node, blender_object)
+
     for frame in range(first_frame, last_frame):
         scene.frame_set(frame)
         obj_xform_mats.append(blender_object.matrix_local.copy())
-        if blender_object.pose is not None:
+        if has_pbone_actions:
             for pbone in blender_object.pose.bones:
+                pbone_parent = pbone_parent_map[pbone.name]
+                if pbone_parent is None:
+                    bone_space_xform = (
+                        pbone.bone.matrix_local.inverted_safe() @ pbone.matrix)
+                else:
+                    bone_space_xform = (
+                        godot_node.find_bone_rest(pbone.name).inverted_safe() @
+                        pbone_parent.matrix.inverted_safe() @
+                        pbone.matrix)
+
                 if pbone.name not in pbone_xform_mats:
                     pbone_xform_mats[pbone.name] = list()
-                pbone_xform_mats[pbone.name].append(
-                    blender_object.convert_space(
-                        pose_bone=pbone, matrix=pbone.matrix,
-                        from_space='POSE', to_space='LOCAL'
-                    )
-                )
+                pbone_xform_mats[pbone.name].append(bone_space_xform)
     scene.frame_set(frame_backup)
 
     if (check_object_constraint(blender_object) or
@@ -153,26 +176,27 @@ def export_constrained_xform_action(godot_node, animation_player,
             # no need for parent_inverse, as it is directly access matrix_local
         )
 
-    for pbone_name, pbone_xform_mat_list in pbone_xform_mats.items():
-        if godot_node.find_bone_id(pbone_name) != -1:
-            pbone_xform_frames_list = [
-                TransformFrame.factory(mat)
-                for mat in pbone_xform_mat_list
-            ]
+    if has_pbone_actions:
+        for pbone_name, pbone_xform_mat_list in pbone_xform_mats.items():
+            if godot_node.find_bone_id(pbone_name) != -1:
+                pbone_xform_frames_list = [
+                    TransformFrame.factory(mat)
+                    for mat in pbone_xform_mat_list
+                ]
 
-            track_path = NodePath(
-                animation_player.parent.get_path(),
-                godot_node.get_path(),
-                godot_node.find_bone_name(pbone_name),
-            )
+                track_path = NodePath(
+                    animation_player.parent.get_path(),
+                    godot_node.get_path(),
+                    godot_node.find_bone_name(pbone_name),
+                )
 
-            animation_resource.add_track(
-                TransformTrack(
-                    track_path,
-                    frames_iter=range(first_frame, last_frame),
-                    values_iter=pbone_xform_frames_list,
+                animation_resource.add_track(
+                    TransformTrack(
+                        track_path,
+                        frames_iter=range(first_frame, last_frame),
+                        values_iter=pbone_xform_frames_list,
+                    )
                 )
-            )
 
 
 def export_transform_action(godot_node, animation_player, blender_object,
@@ -187,7 +211,7 @@ def export_transform_action(godot_node, animation_player, blender_object,
             # bone fcurve in a non armature object
             if godot_node.get_type() != 'Skeleton':
                 logging.warning(
-                    "Skip a bone fcurve in a non-armature "
+                    "Skip bone fcurves of Armature object not being exported. "
                     "object '%s'",
                     blender_object.name
                 )

+ 8 - 0
io_scene_godot/converters/armature.py

@@ -112,6 +112,14 @@ class SkeletonNode(NodeTemplate):
             return ""
         return self.bones[bl_bone_name].name
 
+    def find_bone_rest(self, bl_bone_name):
+        """Given a blender bone name , return its rest matrix"""
+        gd_bone_id = self.find_bone_id(bl_bone_name)
+        if gd_bone_id == -1 or gd_bone_id >= len(self.bones):
+            return mathutils.Matrix.Identity(4)
+        bone_rest_key = 'bones/{}/rest'.format(gd_bone_id)
+        return self[bone_rest_key]
+
     def add_bones(self, bone_list):
         """Add a list of bone to skeleton node"""
         # need first add all bones into name_to_id_map,

+ 13 - 5
io_scene_godot/export_godot.py

@@ -96,9 +96,15 @@ class GodotExporter:
                 obj in self.exporting_objects):
             exporter = converters.BLENDER_TYPE_TO_EXPORTER[obj.type]
         else:
-            logging.warning(
-                "Unknown object type. Treating as empty: %s", obj.name
-            )
+            if obj not in self.exporting_objects:
+                logging.warning(
+                    "Object is parent of exported objects. "
+                    "Treating as empty: %s", obj.name
+                )
+            else:
+                logging.warning(
+                    "Unknown object type. Treating as empty: %s", obj.name
+                )
             exporter = converters.BLENDER_TYPE_TO_EXPORTER["EMPTY"]
 
         is_bone_attachment = False
@@ -171,10 +177,10 @@ class GodotExporter:
 
         # Decide what objects to export
         for obj in self.scene.objects:
-            if obj in self.valid_objects:
+            if obj in self.exporting_objects:
                 continue
             if self.should_export_object(obj):
-                # Ensure  parents of current valid object is
+                # Ensure parents of current valid object is
                 # going to the exporting recursion
                 tmp = obj
                 while tmp is not None:
@@ -226,6 +232,8 @@ class GodotExporter:
         # valid object would contain object should be exported
         # and their parents to retain the hierarchy
         self.valid_objects = set()
+        # exporting objects would only contain objects need
+        # to be exported
         self.exporting_objects = set()
 
         self.escn_file = None

File diff suppressed because it is too large
+ 0 - 0
tests/reference_exports/action_with_constraint/bone_attachment_ik.escn


File diff suppressed because it is too large
+ 0 - 0
tests/reference_exports/action_with_constraint/constraint_external_IK.escn


File diff suppressed because it is too large
+ 0 - 0
tests/reference_exports/action_with_constraint/constraint_internal_IK.escn


File diff suppressed because it is too large
+ 10 - 0
tests/reference_exports/action_with_constraint/constraint_with_undeform_bone.escn


File diff suppressed because it is too large
+ 0 - 0
tests/reference_exports/action_with_constraint/stashed_constraint.escn


+ 3 - 1
tests/reference_exports/material_cycle/material_cycle.escn

@@ -1678,8 +1678,10 @@ mesh = SubResource(15)
 visible = true
 transform = Transform(0.106031, 0.0, 0.0, 0.0, 0.106031, 0.0, 0.0, 0.0, 0.106031, -2.73547, 0.200765, 0.454187)
 
-[node name="Base" type="Spatial" parent="."]
+[node name="Base" type="MeshInstance" parent="."]
 
+mesh = SubResource(15)
+visible = true
 transform = Transform(0.106031, 0.0, 0.0, 0.0, 0.106031, 0.0, 0.0, 0.0, 0.106031, 0.0295276, 0.178654, 0.462086)
 
 [node name="TextBase" type="MeshInstance" parent="Base"]

BIN
tests/test_scenes/action_with_constraint/constraint_with_undeform_bone.blend


Some files were not shown because too many files changed in this diff