[Bf-extensions-cvs] [75855d72] master: glTF importer: fix skinning & hierarchy issues

Julien Duroure noreply at git.blender.org
Thu Jan 23 22:12:13 CET 2020


Commit: 75855d723895e25da855087bccbd0266773bad15
Author: Julien Duroure
Date:   Thu Jan 23 22:10:48 2020 +0100
Branches: master
https://developer.blender.org/rBA75855d723895e25da855087bccbd0266773bad15

glTF importer: fix skinning & hierarchy issues

See https://github.com/KhronosGroup/glTF-Blender-IO/pull/857 for details

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

M	io_scene_gltf2/__init__.py
M	io_scene_gltf2/blender/com/gltf2_blender_conversion.py
M	io_scene_gltf2/blender/imp/gltf2_blender_animation.py
M	io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py
M	io_scene_gltf2/blender/imp/gltf2_blender_animation_node.py
M	io_scene_gltf2/blender/imp/gltf2_blender_animation_weight.py
M	io_scene_gltf2/blender/imp/gltf2_blender_camera.py
M	io_scene_gltf2/blender/imp/gltf2_blender_gltf.py
M	io_scene_gltf2/blender/imp/gltf2_blender_light.py
M	io_scene_gltf2/blender/imp/gltf2_blender_mesh.py
M	io_scene_gltf2/blender/imp/gltf2_blender_node.py
M	io_scene_gltf2/blender/imp/gltf2_blender_primitive.py
M	io_scene_gltf2/blender/imp/gltf2_blender_scene.py
M	io_scene_gltf2/blender/imp/gltf2_blender_skin.py
A	io_scene_gltf2/blender/imp/gltf2_blender_vnode.py
D	io_scene_gltf2/io/com/gltf2_io_trs.py
M	io_scene_gltf2/io/imp/gltf2_io_gltf.py

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

diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py
index 092bb830..f051b08e 100755
--- a/io_scene_gltf2/__init__.py
+++ b/io_scene_gltf2/__init__.py
@@ -15,7 +15,7 @@
 bl_info = {
     'name': 'glTF 2.0 format',
     'author': 'Julien Duroure, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
-    "version": (1, 2, 4),
+    "version": (1, 2, 5),
     'blender': (2, 81, 6),
     'location': 'File > Import-Export',
     'description': 'Import-Export as glTF 2.0',
diff --git a/io_scene_gltf2/blender/com/gltf2_blender_conversion.py b/io_scene_gltf2/blender/com/gltf2_blender_conversion.py
index 6d9a901a..fccfce95 100755
--- a/io_scene_gltf2/blender/com/gltf2_blender_conversion.py
+++ b/io_scene_gltf2/blender/com/gltf2_blender_conversion.py
@@ -15,38 +15,6 @@
 from mathutils import Matrix, Quaternion
 from math import sqrt, sin, cos
 
-def matrix_gltf_to_blender(mat_input):
-    """Matrix from glTF format to Blender format."""
-    mat = Matrix([mat_input[0:4], mat_input[4:8], mat_input[8:12], mat_input[12:16]])
-    mat.transpose()
-    return mat
-
-def loc_gltf_to_blender(loc):
-    """Location."""
-    return loc
-
-def scale_gltf_to_blender(scale):
-    """Scaling."""
-    return scale
-
-def quaternion_gltf_to_blender(q):
-    """Quaternion from glTF to Blender."""
-    return Quaternion([q[3], q[0], q[1], q[2]])
-
-def scale_to_matrix(scale):
-    """Scale to matrix."""
-    mat = Matrix()
-    for i in range(3):
-        mat[i][i] = scale[i]
-
-    return mat
-
-def correction_rotation():
-    """Correction of Rotation."""
-    # Correction is needed for lamps, because Yup2Zup is not written in vertices
-    # and lamps has no vertices :)
-    return Quaternion((sqrt(2)/2, -sqrt(2)/2, 0.0, 0.0)).to_matrix().to_4x4()
-
 def texture_transform_blender_to_gltf(mapping_transform):
     """
     Converts the offset/rotation/scale from a Mapping node applied in Blender's
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_animation.py b/io_scene_gltf2/blender/imp/gltf2_blender_animation.py
index 6394145d..ed1d938d 100755
--- a/io_scene_gltf2/blender/imp/gltf2_blender_animation.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_animation.py
@@ -18,6 +18,7 @@ from .gltf2_blender_animation_bone import BlenderBoneAnim
 from .gltf2_blender_animation_node import BlenderNodeAnim
 from .gltf2_blender_animation_weight import BlenderWeightAnim
 from .gltf2_blender_animation_utils import restore_animation_on_object
+from .gltf2_blender_vnode import VNode
 
 
 class BlenderAnimation():
@@ -26,34 +27,36 @@ class BlenderAnimation():
         raise RuntimeError("%s should not be instantiated" % cls)
 
     @staticmethod
-    def anim(gltf, anim_idx, node_idx):
+    def anim(gltf, anim_idx, vnode_id):
         """Dispatch Animation to bone or object."""
-        if gltf.data.nodes[node_idx].is_joint:
-            BlenderBoneAnim.anim(gltf, anim_idx, node_idx)
-        else:
-            BlenderNodeAnim.anim(gltf, anim_idx, node_idx)
-            BlenderWeightAnim.anim(gltf, anim_idx, node_idx)
+        if isinstance(vnode_id, int):
+            if gltf.vnodes[vnode_id].type == VNode.Bone:
+                BlenderBoneAnim.anim(gltf, anim_idx, vnode_id)
+            elif gltf.vnodes[vnode_id].type == VNode.Object:
+                BlenderNodeAnim.anim(gltf, anim_idx, vnode_id)
 
-        if gltf.data.nodes[node_idx].children:
-            for child in gltf.data.nodes[node_idx].children:
-                BlenderAnimation.anim(gltf, anim_idx, child)
+        BlenderWeightAnim.anim(gltf, anim_idx, vnode_id)
+
+        for child in gltf.vnodes[vnode_id].children:
+            BlenderAnimation.anim(gltf, anim_idx, child)
 
     @staticmethod
-    def restore_animation(gltf, node_idx, animation_name):
+    def restore_animation(gltf, vnode_id, animation_name):
         """Restores the actions for an animation by its track name on
         the subtree starting at node_idx."""
-        node = gltf.data.nodes[node_idx]
+        vnode = gltf.vnodes[vnode_id]
 
-        if node.is_joint:
-            obj = bpy.data.objects[gltf.data.skins[node.skin_id].blender_armature_name]
-        else:
-            obj = bpy.data.objects[node.blender_object]
+        obj = None
+        if vnode.type == VNode.Bone:
+            obj = gltf.vnodes[vnode.bone_arma].blender_object
+        elif vnode.type == VNode.Object:
+            obj = vnode.blender_object
 
-        restore_animation_on_object(obj, animation_name)
-        if obj.data and hasattr(obj.data, 'shape_keys'):
-            restore_animation_on_object(obj.data.shape_keys, animation_name)
+        if obj is not None:
+            restore_animation_on_object(obj, animation_name)
+            if obj.data and hasattr(obj.data, 'shape_keys'):
+                restore_animation_on_object(obj.data.shape_keys, animation_name)
 
-        if gltf.data.nodes[node_idx].children:
-            for child in gltf.data.nodes[node_idx].children:
-                BlenderAnimation.restore_animation(gltf, child, animation_name)
+        for child in gltf.vnodes[vnode_id].children:
+            BlenderAnimation.restore_animation(gltf, child, animation_name)
 
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py b/io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py
index 465a801d..7e32487c 100755
--- a/io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py
@@ -14,51 +14,56 @@
 
 import json
 import bpy
-from mathutils import Matrix
+from mathutils import Vector
 
-from ..com.gltf2_blender_conversion import loc_gltf_to_blender, quaternion_gltf_to_blender, scale_to_matrix
 from ...io.imp.gltf2_io_binary import BinaryData
 from .gltf2_blender_animation_utils import simulate_stash, make_fcurve
 
 
+# The glTF curves store the value of the final transform, but in Blender
+# curves animate a pose bone that is relative to the edit bone
+#
+#     Final = EditBone * PoseBone
+#   where
+#     Final =    Trans[ft] Rot[fr] Scale[fs]
+#     EditBone = Trans[et] Rot[er]                (edit bones have no scale)
+#     PoseBone = Trans[pt] Rot[pr] Scale[ps]
+#
+# Solving for the PoseBone gives the change we need to apply to the curves
+#
+#     pt = Rot[er^{-1}] (ft - et)
+#     pr = er^{-1} fr
+#     ps = fs
+
 class BlenderBoneAnim():
     """Blender Bone Animation."""
     def __new__(cls, *args, **kwargs):
         raise RuntimeError("%s should not be instantiated" % cls)
 
     @staticmethod
-    def parse_translation_channel(gltf, node, obj, bone, channel, animation):
+    def parse_translation_channel(gltf, vnode, obj, bone, channel, animation):
         """Manage Location animation."""
         blender_path = "pose.bones[" + json.dumps(bone.name) + "].location"
         group_name = bone.name
 
         keys = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].input)
         values = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].output)
-        inv_bind_matrix = node.blender_bone_matrix.to_quaternion().to_matrix().to_4x4().inverted() \
-            @ Matrix.Translation(node.blender_bone_matrix.to_translation()).inverted()
 
         if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
             # TODO manage tangent?
             translation_keyframes = (
-                loc_gltf_to_blender(values[idx * 3 + 1])
+                gltf.loc_gltf_to_blender(values[idx * 3 + 1])
                 for idx in range(0, len(keys))
             )
         else:
-            translation_keyframes = (loc_gltf_to_blender(vals) for vals in values)
-        if node.parent is None:
-            parent_mat = Matrix()
-        else:
-            if not gltf.data.nodes[node.parent].is_joint:
-                parent_mat = Matrix()
-            else:
-                parent_mat = gltf.data.nodes[node.parent].blender_bone_matrix
-
-        # Pose is in object (armature) space and it's value if the offset from the bind pose
-        # (which is also in object space)
-        # Scale is not taken into account
+            translation_keyframes = (gltf.loc_gltf_to_blender(vals) for vals in values)
+
+        bind_trans, bind_rot, _ = vnode.trs
+        bind_rot_inv = bind_rot.conjugated()
+
         final_translations = [
-            inv_bind_matrix @ (parent_mat @ Matrix.Translation(translation_keyframe)).to_translation()
-            for translation_keyframe in translation_keyframes
+            bind_rot_inv @ (trans - bind_trans)
+            for trans in translation_keyframes
         ]
 
         BlenderBoneAnim.fill_fcurves(
@@ -71,48 +76,31 @@ class BlenderBoneAnim():
         )
 
     @staticmethod
-    def parse_rotation_channel(gltf, node, obj, bone, channel, animation):
+    def parse_rotation_channel(gltf, vnode, obj, bone, channel, animation):
         """Manage rotation animation."""
         blender_path = "pose.bones[" + json.dumps(bone.name) + "].rotation_quaternion"
         group_name = bone.name
 
         keys = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].input)
         values = BinaryData.get_data_from_accessor(gltf, animation.samplers[channel.sampler].output)
-        bind_rotation = node.blender_bone_matrix.to_quaternion()
 
         if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
             # TODO manage tangent?
             quat_keyframes = [
-                quaternion_gltf_to_blender(values[idx * 3 + 1])
+                gltf.quaternion_gltf_to_blender(values[idx * 3 + 1])
                 for idx in range(0, len(keys))
             ]
         else:
-            quat_keyframes = [quaternion_gltf_to_blender(vals) for vals in values]
+            quat_keyframes = [gltf.quaternion_gltf_to_blender(vals) for vals in values]
 
+        _, bind_rot, _ = vnode.trs
+        bind_rot_inv = bind_rot.conjugated()
 
-        if node.parent is None:
-            final_rots = [
-                bind_rotation.inverted() @ quat_keyframe
-                for quat_keyframe in quat_keyframes
-            ]
-        else:
-            if not gltf.data.nodes[node

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list