From 72227fc13ba354695244a600b0d8b6a0b5d6f460 Mon Sep 17 00:00:00 2001 From: Julien Duroure Date: Tue, 12 May 2020 18:43:44 +0200 Subject: glTF exporter: prevent infinite recursion when mesh is skinned and parenting to same bone Avoid this by do not skin if object is parented to a bone of the armature that skin the object: keep only parenting to bone --- io_scene_gltf2/__init__.py | 2 +- .../blender/exp/gltf2_blender_extract.py | 111 +++++++++++---------- .../blender/exp/gltf2_blender_gather_nodes.py | 9 ++ 3 files changed, 69 insertions(+), 53 deletions(-) diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py index 50a313fb..2825fa3c 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, 3, 14), + "version": (1, 3, 15), 'blender': (2, 90, 0), 'location': 'File > Import-Export', 'description': 'Import-Export as glTF 2.0', diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_extract.py b/io_scene_gltf2/blender/exp/gltf2_blender_extract.py index 35f31c50..e2d224ce 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_extract.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_extract.py @@ -409,63 +409,70 @@ def extract_primitives(glTF, blender_mesh, library, blender_object, blender_vert bone_count = 0 - if blender_vertex_groups is not None and vertex.groups is not None and len(vertex.groups) > 0 and export_settings[gltf2_blender_export_keys.SKINS]: - joint = [] - weight = [] - vertex_groups = vertex.groups - if not export_settings['gltf_all_vertex_influences']: - # sort groups by weight descending - vertex_groups = sorted(vertex.groups, key=attrgetter('weight'), reverse=True) - for group_element in vertex_groups: - - if len(joint) == 4: - bone_count += 1 - joints.append(joint) - weights.append(weight) - joint = [] - weight = [] - - # - - joint_weight = group_element.weight - if joint_weight <= 0.0: - continue - - # - - vertex_group_index = group_element.group - - if vertex_group_index < 0 or vertex_group_index >= len(blender_vertex_groups): - continue - vertex_group_name = blender_vertex_groups[vertex_group_index].name + # Skin must be ignored if the object is parented to a bone of the armature + # (This creates an infinite recursive error) + # So ignoring skin in that case + if blender_object and blender_object.parent_type == "BONE" and blender_object.parent.name == armature.name: + bone_max = 0 # joints & weights will be ignored in following code + else: + # Manage joints & weights + if blender_vertex_groups is not None and vertex.groups is not None and len(vertex.groups) > 0 and export_settings[gltf2_blender_export_keys.SKINS]: + joint = [] + weight = [] + vertex_groups = vertex.groups + if not export_settings['gltf_all_vertex_influences']: + # sort groups by weight descending + vertex_groups = sorted(vertex.groups, key=attrgetter('weight'), reverse=True) + for group_element in vertex_groups: + + if len(joint) == 4: + bone_count += 1 + joints.append(joint) + weights.append(weight) + joint = [] + weight = [] + + # + + joint_weight = group_element.weight + if joint_weight <= 0.0: + continue + + # + + vertex_group_index = group_element.group + + if vertex_group_index < 0 or vertex_group_index >= len(blender_vertex_groups): + continue + vertex_group_name = blender_vertex_groups[vertex_group_index].name + + joint_index = None + + if armature: + skin = gltf2_blender_gather_skins.gather_skin(armature, export_settings) + for index, j in enumerate(skin.joints): + if j.name == vertex_group_name: + joint_index = index + break - joint_index = None + # + if joint_index is not None: + joint.append(joint_index) + weight.append(joint_weight) - if armature: - skin = gltf2_blender_gather_skins.gather_skin(armature, export_settings) - for index, j in enumerate(skin.joints): - if j.name == vertex_group_name: - joint_index = index - break - - # - if joint_index is not None: - joint.append(joint_index) - weight.append(joint_weight) - - if len(joint) > 0: - bone_count += 1 + if len(joint) > 0: + bone_count += 1 - for fill in range(0, 4 - len(joint)): - joint.append(0) - weight.append(0.0) + for fill in range(0, 4 - len(joint)): + joint.append(0) + weight.append(0.0) - joints.append(joint) - weights.append(weight) + joints.append(joint) + weights.append(weight) - for fill in range(0, bone_max - bone_count): - joints.append([0, 0, 0, 0]) - weights.append([0.0, 0.0, 0.0, 0.0]) + for fill in range(0, bone_max - bone_count): + joints.append([0, 0, 0, 0]) + weights.append([0.0, 0.0, 0.0, 0.0]) # diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py index 3b0fab2d..548c5299 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_nodes.py @@ -409,6 +409,15 @@ def __gather_skin(blender_object, export_settings): if not any(vertex.groups is not None and len(vertex.groups) > 0 for vertex in blender_mesh.vertices): return None + # Prevent infinite recursive error. A mesh can't have an Armature modifier + # and be bone parented to a bone of this armature + # In that case, ignore the armature modifier, keep only the bone parenting + if blender_object.parent is not None \ + and blender_object.parent_type == 'BONE' \ + and blender_object.parent.name == modifiers["ARMATURE"].object.name: + + return None + # Skins and meshes must be in the same glTF node, which is different from how blender handles armatures return gltf2_blender_gather_skins.gather_skin(modifiers["ARMATURE"].object, export_settings) -- cgit v1.2.3