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
This commit is contained in:
Julien Duroure 2020-05-12 18:43:44 +02:00
parent 64d3439667
commit 72227fc13b
3 changed files with 69 additions and 53 deletions

View File

@ -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',

View File

@ -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:
# 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:
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
#
if joint_index is not None:
joint.append(joint_index)
weight.append(joint_weight)
if len(joint) > 0:
bone_count += 1
for fill in range(0, 4 - len(joint)):
joint.append(0)
weight.append(0.0)
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
#
if joint_index is not None:
joint.append(joint_index)
weight.append(joint_weight)
if len(joint) > 0:
bone_count += 1
for fill in range(0, 4 - len(joint)):
joint.append(0)
weight.append(0.0)
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])
#

View File

@ -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)