diff options
author | Julien Duroure <julien.duroure@gmail.com> | 2020-01-24 00:10:48 +0300 |
---|---|---|
committer | Julien Duroure <julien.duroure@gmail.com> | 2020-01-24 00:10:48 +0300 |
commit | 75855d723895e25da855087bccbd0266773bad15 (patch) | |
tree | c4d159ce2e5921f2d9239cc641c02746f173d5ed /io_scene_gltf2/blender/imp/gltf2_blender_gltf.py | |
parent | b3b274c5739de01685572032ac26ac5dcb50b950 (diff) |
glTF importer: fix skinning & hierarchy issues
See https://github.com/KhronosGroup/glTF-Blender-IO/pull/857 for details
Diffstat (limited to 'io_scene_gltf2/blender/imp/gltf2_blender_gltf.py')
-rwxr-xr-x | io_scene_gltf2/blender/imp/gltf2_blender_gltf.py | 156 |
1 files changed, 45 insertions, 111 deletions
diff --git a/io_scene_gltf2/blender/imp/gltf2_blender_gltf.py b/io_scene_gltf2/blender/imp/gltf2_blender_gltf.py index 5904a974..7b259759 100755 --- a/io_scene_gltf2/blender/imp/gltf2_blender_gltf.py +++ b/io_scene_gltf2/blender/imp/gltf2_blender_gltf.py @@ -13,8 +13,8 @@ # limitations under the License. import bpy +from mathutils import Vector, Quaternion, Matrix from .gltf2_blender_scene import BlenderScene -from ...io.com.gltf2_io_trs import TRS class BlenderGlTF(): @@ -25,79 +25,52 @@ class BlenderGlTF(): @staticmethod def create(gltf): """Create glTF main method.""" - if bpy.context.scene.render.engine not in ['CYCLES', 'BLENDER_EEVEE']: - bpy.context.scene.render.engine = 'BLENDER_EEVEE' + BlenderGlTF.set_convert_functions(gltf) BlenderGlTF.pre_compute(gltf) + BlenderScene.create(gltf) + + @staticmethod + def set_convert_functions(gltf): + yup2zup = bpy.app.debug_value != 100 + + if yup2zup: + # glTF Y-Up space --> Blender Z-up space + # X,Y,Z --> X,-Z,Y + def convert_loc(x): return Vector([x[0], -x[2], x[1]]) + def convert_quat(q): return Quaternion([q[3], q[0], -q[2], q[1]]) + def convert_normal(n): return Vector([n[0], -n[2], n[1]]) + def convert_scale(s): return Vector([s[0], s[2], s[1]]) + def convert_matrix(m): + return Matrix([ + [ m[0], -m[ 8], m[4], m[12]], + [-m[2], m[10], -m[6], -m[14]], + [ m[1], -m[ 9], m[5], m[13]], + [ m[3], -m[11], m[7], m[15]], + ]) + + # Correction for cameras and lights. + # glTF: right = +X, forward = -Z, up = +Y + # glTF after Yup2Zup: right = +X, forward = +Y, up = +Z + # Blender: right = +X, forward = -Z, up = +Y + # Need to carry Blender --> glTF after Yup2Zup + gltf.camera_correction = Quaternion((2**0.5/2, 2**0.5/2, 0.0, 0.0)) - gltf.display_current_node = 0 - if gltf.data.nodes is not None: - gltf.display_total_nodes = len(gltf.data.nodes) - else: - gltf.display_total_nodes = "?" - - active_object_name_at_end = None - if gltf.data.scenes is not None: - for scene_idx, scene in enumerate(gltf.data.scenes): - BlenderScene.create(gltf, scene_idx) - # keep active object name if needed (to be able to set as active object at end) - if gltf.data.scene is not None: - if scene_idx == gltf.data.scene: - active_object_name_at_end = bpy.context.view_layer.objects.active.name - else: - if scene_idx == 0: - active_object_name_at_end = bpy.context.view_layer.objects.active.name else: - # special case where there is no scene in glTF file - # generate all objects in current scene - BlenderScene.create(gltf, None) - active_object_name_at_end = bpy.context.view_layer.objects.active.name - - # Armature correction - # Try to detect bone chains, and set bone lengths - # To detect if a bone is in a chain, we try to detect if a bone head is aligned - # with parent_bone : - # Parent bone defined a line (between head & tail) - # Bone head defined a point - # Calcul of distance between point and line - # If < threshold --> In a chain - # Based on an idea of @Menithal, but added alignment detection to avoid some bad cases - - threshold = 0.001 - for armobj in [obj for obj in bpy.data.objects if obj.type == "ARMATURE"]: - # Take into account only armature from this scene - if armobj.name not in bpy.context.view_layer.objects: - continue - bpy.context.view_layer.objects.active = armobj - armature = armobj.data - bpy.ops.object.mode_set(mode="EDIT") - for bone in armature.edit_bones: - if bone.parent is None: - continue - - parent = bone.parent - - # case where 2 bones are aligned (not in chain, same head) - if (bone.head - parent.head).length < threshold: - continue - - u = (parent.tail - parent.head).normalized() - point = bone.head - distance = ((point - parent.head).cross(u)).length / u.length - if distance < threshold: - save_parent_direction = (parent.tail - parent.head).normalized().copy() - save_parent_tail = parent.tail.copy() - parent.tail = bone.head - - # case where 2 bones are aligned (not in chain, same head) - # bone is no more is same direction - if (parent.tail - parent.head).normalized().dot(save_parent_direction) < 0.9: - parent.tail = save_parent_tail - - bpy.ops.object.mode_set(mode="OBJECT") - - # Set active object - if active_object_name_at_end is not None: - bpy.context.view_layer.objects.active = bpy.data.objects[active_object_name_at_end] + def convert_loc(x): return Vector(x) + def convert_quat(q): return Quaternion([q[3], q[0], q[1], q[2]]) + def convert_normal(n): return Vector(n) + def convert_scale(s): return Vector(s) + def convert_matrix(m): + return Matrix([m[0::4], m[1::4], m[2::4], m[3::4]]) + + # Same convention, no correction needed. + gltf.camera_correction = None + + gltf.loc_gltf_to_blender = convert_loc + gltf.quaternion_gltf_to_blender = convert_quat + gltf.normal_gltf_to_blender = convert_normal + gltf.scale_gltf_to_blender = convert_scale + gltf.matrix_gltf_to_blender = convert_matrix @staticmethod def pre_compute(gltf): @@ -208,45 +181,6 @@ class BlenderGlTF(): # Lights management node.correction_needed = False - # transform management - if node.matrix: - node.transform = node.matrix - continue - - # No matrix, but TRS - mat = [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0] # init - - if node.scale: - mat = TRS.scale_to_matrix(node.scale) - - if node.rotation: - q_mat = TRS.quaternion_to_matrix(node.rotation) - mat = TRS.matrix_multiply(q_mat, mat) - - if node.translation: - loc_mat = TRS.translation_to_matrix(node.translation) - mat = TRS.matrix_multiply(loc_mat, mat) - - node.transform = mat - - - # joint management - for node_idx, node in enumerate(gltf.data.nodes): - is_joint, skin_idx = gltf.is_node_joint(node_idx) - if is_joint: - node.is_joint = True - node.skin_id = skin_idx - else: - node.is_joint = False - - if gltf.data.skins: - for skin_id, skin in enumerate(gltf.data.skins): - # init blender values - skin.blender_armature_name = None - # if skin.skeleton and skin.skeleton not in skin.joints: - # gltf.data.nodes[skin.skeleton].is_joint = True - # gltf.data.nodes[skin.skeleton].skin_id = skin_id - # Dispatch animation if gltf.data.animations: for node_idx, node in enumerate(gltf.data.nodes): @@ -274,7 +208,7 @@ class BlenderGlTF(): # Meshes if gltf.data.meshes: for mesh in gltf.data.meshes: - mesh.blender_name = None + mesh.blender_name = {} # cache Blender mesh (keyed by skin_idx) mesh.is_weight_animated = False # Calculate names for each mesh's shapekeys |