[Bf-extensions-cvs] [b4fc9fbc] master: glTF importer: code cleanup. Better distinction between edit / pose / bind pose

Julien Duroure noreply at git.blender.org
Sun Feb 23 11:47:37 CET 2020


Commit: b4fc9fbcf4e2d766143d6e88b57e892a12b6fe88
Author: Julien Duroure
Date:   Sun Feb 23 11:46:59 2020 +0100
Branches: master
https://developer.blender.org/rBAb4fc9fbcf4e2d766143d6e88b57e892a12b6fe88

glTF importer: code cleanup. Better distinction between edit / pose / bind pose

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

M	io_scene_gltf2/__init__.py
M	io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.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_vnode.py

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

diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py
index 07434951..e13b4cfc 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, 26),
+    "version": (1, 2, 27),
     'blender': (2, 82, 7),
     'location': 'File > Import-Export',
     'description': 'Import-Export as glTF 2.0',
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 96524d5b..4d834611 100755
--- a/io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py
@@ -20,8 +20,8 @@ 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
+# In Blender we animate a pose bone. The final TRS of the bone depends on
+# both the edit bone and pose bone
 #
 #     Final = EditBone * PoseBone
 #   where
@@ -29,7 +29,7 @@ from .gltf2_blender_animation_utils import simulate_stash, make_fcurve
 #     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
+# Given Final we can solve for the PoseBone we need to use with
 #
 #     pt = Rot[er^{-1}] (ft - et)
 #     pr = er^{-1} fr
@@ -58,18 +58,18 @@ class BlenderBoneAnim():
         else:
             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 = [
-            bind_rot_inv @ (trans - bind_trans)
+        # Calculate pose bone trans from final bone trans
+        edit_trans, edit_rot = vnode.editbone_trans, vnode.editbone_rot
+        edit_rot_inv = edit_rot.conjugated()
+        pose_translations = [
+            edit_rot_inv @ (trans - edit_trans)
             for trans in translation_keyframes
         ]
 
         BlenderBoneAnim.fill_fcurves(
             obj.animation_data.action,
             keys,
-            final_translations,
+            pose_translations,
             group_name,
             blender_path,
             animation.samplers[channel.sampler].interpolation
@@ -93,24 +93,23 @@ class BlenderBoneAnim():
         else:
             quat_keyframes = [gltf.quaternion_gltf_to_blender(vals) for vals in values]
 
-        _, bind_rot, _ = vnode.trs
-        bind_rot_inv = bind_rot.conjugated()
-
-
-        final_rots = [
-            bind_rot_inv @ rot
+        # Calculate pose bone rotation from final bone rotation
+        edit_rot = vnode.editbone_rot
+        edit_rot_inv = edit_rot.conjugated()
+        pose_rots = [
+            edit_rot_inv @ rot
             for rot in quat_keyframes
         ]
 
         # Manage antipodal quaternions
-        for i in range(1, len(final_rots)):
-            if final_rots[i].dot(final_rots[i-1]) < 0:
-                final_rots[i] = -final_rots[i]
+        for i in range(1, len(pose_rots)):
+            if pose_rots[i].dot(pose_rots[i-1]) < 0:
+                pose_rots[i] = -pose_rots[i]
 
         BlenderBoneAnim.fill_fcurves(
             obj.animation_data.action,
             keys,
-            final_rots,
+            pose_rots,
             group_name,
             blender_path,
             animation.samplers[channel.sampler].interpolation
@@ -127,17 +126,17 @@ class BlenderBoneAnim():
 
         if animation.samplers[channel.sampler].interpolation == "CUBICSPLINE":
             # TODO manage tangent?
-            final_scales = [
+            scale_keyframes = [
                 gltf.scale_gltf_to_blender(values[idx * 3 + 1])
                 for idx in range(0, len(keys))
             ]
         else:
-            final_scales = [gltf.scale_gltf_to_blender(vals) for vals in values]
+            scale_keyframes = [gltf.scale_gltf_to_blender(vals) for vals in values]
 
         BlenderBoneAnim.fill_fcurves(
             obj.animation_data.action,
             keys,
-            final_scales,
+            scale_keyframes,
             group_name,
             blender_path,
             animation.samplers[channel.sampler].interpolation
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_node.py b/io_scene_gltf2/blender/imp/gltf2_blender_node.py
index bab22599..590a4fa5 100755
--- a/io_scene_gltf2/blender/imp/gltf2_blender_node.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_node.py
@@ -134,7 +134,7 @@ class BlenderNode():
             editbone.use_connect = False  # TODO?
 
             # Give the position of the bone in armature space
-            arma_mat = vnode.bone_arma_mat
+            arma_mat = vnode.editbone_arma_mat
             editbone.head = arma_mat @ Vector((0, 0, 0))
             editbone.tail = arma_mat @ Vector((0, 1, 0))
             editbone.align_roll(arma_mat @ Vector((0, 0, 1)) - editbone.head)
@@ -159,8 +159,13 @@ class BlenderNode():
             vnode = gltf.vnodes[id]
             pose_bone = blender_arma.pose.bones[vnode.blender_bone_name]
 
-            # Put scale on pose bone (edit bones have no scale)
-            _, _, s = vnode.trs
+            # BoneTRS = EditBone * PoseBone
+            # Set PoseBone to make BoneTRS = vnode.trs.
+            t, r, s = vnode.trs
+            et, er = vnode.editbone_trans, vnode.editbone_rot
+            pose_bone.location = er.conjugated() @ (t - et)
+            pose_bone.rotation_mode = 'QUATERNION'
+            pose_bone.rotation_quaternion = er.conjugated() @ r
             pose_bone.scale = s
 
             if isinstance(id, int):
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_primitive.py b/io_scene_gltf2/blender/imp/gltf2_blender_primitive.py
index fb515e0f..07030a62 100755
--- a/io_scene_gltf2/blender/imp/gltf2_blender_primitive.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_primitive.py
@@ -78,8 +78,8 @@ class BlenderPrimitive():
                 inv_binds = [gltf.matrix_gltf_to_blender(m) for m in inv_binds]
             else:
                 inv_binds = [Matrix.Identity(4) for i in range(len(pyskin.joints))]
-            arma_mats = [gltf.vnodes[joint].bone_arma_mat for joint in pyskin.joints]
-            joint_mats = [arma_mat @ inv_bind for arma_mat, inv_bind in zip(arma_mats, inv_binds)]
+            bind_mats = [gltf.vnodes[joint].bind_arma_mat for joint in pyskin.joints]
+            joint_mats = [bind_mat @ inv_bind for bind_mat, inv_bind in zip(bind_mats, inv_binds)]
 
             def skin_vert(pos, pidx):
                 out = Vector((0, 0, 0))
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_vnode.py b/io_scene_gltf2/blender/imp/gltf2_blender_vnode.py
index 8ab0da32..bd5edcd1 100644
--- a/io_scene_gltf2/blender/imp/gltf2_blender_vnode.py
+++ b/io_scene_gltf2/blender/imp/gltf2_blender_vnode.py
@@ -25,6 +25,7 @@ def compute_vnodes(gltf):
     move_skinned_meshes(gltf)
     fixup_multitype_nodes(gltf)
     correct_cameras_and_lights(gltf)
+    pick_bind_pose(gltf)
     calc_bone_matrices(gltf)
 
 
@@ -181,7 +182,7 @@ def move_skinned_meshes(gltf):
      * Move a skinned mesh to become a child of the armature that skins it.
        Have to ensure the mesh and arma have the same world transform.
      * When we do mesh creation, we will also need to put all the verts in
-       their rest pose (ie. the pose the edit bones are in)
+       the bind pose in arma space.
     """
     ids = list(gltf.vnodes.keys())
     for id in ids:
@@ -334,22 +335,46 @@ def correct_cameras_and_lights(gltf):
             vnode.light_node_idx = None
 
 
+def pick_bind_pose(gltf):
+    """
+    Pick the bind pose for all bones. Skinned meshes will be retargeted onto
+    this bind pose during mesh creation.
+    """
+    for vnode_id in gltf.vnodes:
+        vnode = gltf.vnodes[vnode_id]
+        if vnode.type == VNode.Bone:
+            # For now, use the node TR for bind pose.
+            # TODO: try calculating from inverseBindMatices?
+            vnode.bind_trans = Vector(vnode.trs[0])
+            vnode.bind_rot = Quaternion(vnode.trs[1])
+
+            # Initialize editbones to match bind pose
+            vnode.editbone_trans = Vector(vnode.bind_trans)
+            vnode.editbone_rot = Quaternion(vnode.bind_rot)
+
+
 def calc_bone_matrices(gltf):
     """
-    Calculate bone_arma_mat, the transformation from bone space to armature
-    space for the edit bone, for each bone.
+    Calculate the transformations from bone space to arma space in the bind
+    pose and in the edit bone pose.
     """
     def visit(vnode_id):  # Depth-first walk
         vnode = gltf.vnodes[vnode_id]
         if vnode.type == VNode.Bone:
             if gltf.vnodes[vnode.parent].type == VNode.Bone:
-                parent_arma_mat = gltf.vnodes[vnode.parent].bone_arma_mat
+                parent_bind_mat = gltf.vnodes[vnode.parent].bind_arma_mat
+                parent_editbone_mat = gltf.vnodes[vnode.parent].editbone_arma_mat
             else:
-                parent_arma_mat = Matrix.Identity(4)
+                parent_bind_mat = Matrix.Identity(4)
+                parent_editbone_mat = Matrix.Identity(4)
+
+            t, r = vnode.bind_trans, vnode.bind_rot
+            local_to_parent = Matrix.Translation(t) @ Quaternion(r).to_matrix().to_4x4()
+            vnode.bind_arma_mat = parent_bind_mat @ local_to_parent
 
-            t, r, _ = vnode.trs
+            t, r = vnode.editbone_trans, vnode.editbone_rot
             local_to_parent = Matrix.Translation(t) @ Quaternion(r).to_matrix().to_4x4()
-            vnode.bone_arma_mat = parent_arma_mat @ local_to_parent
+            vnode.editbone_arma_mat = parent_editbone_mat @ local_to_parent
 
         for child in vnode.children:
             visit(child)



More information about the Bf-extensions-cvs mailing list