diff options
author | Julien Duroure <julien.duroure@gmail.com> | 2020-02-23 13:46:59 +0300 |
---|---|---|
committer | Julien Duroure <julien.duroure@gmail.com> | 2020-02-23 13:46:59 +0300 |
commit | b4fc9fbcf4e2d766143d6e88b57e892a12b6fe88 (patch) | |
tree | 398f400ccbc505b6e182ff5c1fd433f8c817ed62 /io_scene_gltf2 | |
parent | ffd8a687247da9695857d5b58ce759eecb016c38 (diff) |
glTF importer: code cleanup. Better distinction between edit / pose / bind pose
Diffstat (limited to 'io_scene_gltf2')
-rwxr-xr-x | io_scene_gltf2/__init__.py | 2 | ||||
-rwxr-xr-x | io_scene_gltf2/blender/imp/gltf2_blender_animation_bone.py | 43 | ||||
-rwxr-xr-x | io_scene_gltf2/blender/imp/gltf2_blender_node.py | 11 | ||||
-rwxr-xr-x | io_scene_gltf2/blender/imp/gltf2_blender_primitive.py | 4 | ||||
-rw-r--r-- | io_scene_gltf2/blender/imp/gltf2_blender_vnode.py | 39 |
5 files changed, 64 insertions, 35 deletions
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) |