From 96eb14698456d06bea5a42a6bb35daa172841a6a Mon Sep 17 00:00:00 2001 From: Julien Duroure Date: Fri, 29 Apr 2022 08:29:05 +0200 Subject: glTF exporter: normalize skin weights also for all influence mode --- io_scene_gltf2/__init__.py | 2 +- .../gltf2_blender_gather_primitive_attributes.py | 105 ++++++++++++--------- 2 files changed, 64 insertions(+), 43 deletions(-) diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py index fe391793..c2cd82b3 100755 --- a/io_scene_gltf2/__init__.py +++ b/io_scene_gltf2/__init__.py @@ -4,7 +4,7 @@ bl_info = { 'name': 'glTF 2.0 format', 'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors', - "version": (3, 2, 35), + "version": (3, 2, 36), 'blender': (3, 1, 0), 'location': 'File > Import-Export', 'description': 'Import-Export as glTF 2.0', diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_primitive_attributes.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_primitive_attributes.py index 776b872a..72f0268c 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_primitive_attributes.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_primitive_attributes.py @@ -157,48 +157,69 @@ def __gather_colors(blender_primitive, export_settings): def __gather_skins(blender_primitive, export_settings): attributes = {} - if export_settings[gltf2_blender_export_keys.SKINS]: - bone_set_index = 0 - joint_id = 'JOINTS_' + str(bone_set_index) - weight_id = 'WEIGHTS_' + str(bone_set_index) - while blender_primitive["attributes"].get(joint_id) and blender_primitive["attributes"].get(weight_id): - if bone_set_index >= 1: - if not export_settings['gltf_all_vertex_influences']: - gltf2_io_debug.print_console("WARNING", "There are more than 4 joint vertex influences." - "The 4 with highest weight will be used (and normalized).") - break - - # joints - internal_joint = blender_primitive["attributes"][joint_id] - component_type = gltf2_io_constants.ComponentType.UnsignedShort - if max(internal_joint) < 256: - component_type = gltf2_io_constants.ComponentType.UnsignedByte - joint = array_to_accessor( - internal_joint, - component_type, - data_type=gltf2_io_constants.DataType.Vec4, - ) - attributes[joint_id] = joint - - # weights - internal_weight = blender_primitive["attributes"][weight_id] - # normalize first 4 weights, when not exporting all influences - if not export_settings['gltf_all_vertex_influences']: - for idx in range(0, len(internal_weight), 4): - weight_slice = internal_weight[idx:idx + 4] - total = sum(weight_slice) - if total > 0: - factor = 1.0 / total - internal_weight[idx:idx + 4] = [w * factor for w in weight_slice] - - weight = array_to_accessor( - internal_weight, - component_type=gltf2_io_constants.ComponentType.Float, - data_type=gltf2_io_constants.DataType.Vec4, + + if not export_settings[gltf2_blender_export_keys.SKINS]: + return attributes + + # Retrieve max set index + max_bone_set_index = 0 + while blender_primitive["attributes"].get('JOINTS_' + str(max_bone_set_index)) and blender_primitive["attributes"].get('WEIGHTS_' + str(max_bone_set_index)): + max_bone_set_index += 1 + max_bone_set_index -= 1 + + # If no skinning + if max_bone_set_index < 0: + return attributes + + if max_bone_set_index > 0 and not export_settings['gltf_all_vertex_influences']: + gltf2_io_debug.print_console("WARNING", "There are more than 4 joint vertex influences." + "The 4 with highest weight will be used (and normalized).") + + # Take into account only the first set of 4 weights + max_bone_set_index = 0 + + # Convert weights to numpy arrays, and setting joints + weight_arrs = [] + for s in range(0, max_bone_set_index+1): + + weight_id = 'WEIGHTS_' + str(s) + weight = blender_primitive["attributes"][weight_id] + weight = np.array(weight, dtype=np.float32) + weight = weight.reshape(len(weight) // 4, 4) + weight_arrs.append(weight) + + + # joints + joint_id = 'JOINTS_' + str(s) + internal_joint = blender_primitive["attributes"][joint_id] + component_type = gltf2_io_constants.ComponentType.UnsignedShort + if max(internal_joint) < 256: + component_type = gltf2_io_constants.ComponentType.UnsignedByte + joint = array_to_accessor( + internal_joint, + component_type, + data_type=gltf2_io_constants.DataType.Vec4, + ) + attributes[joint_id] = joint + + # Sum weights for each vertex + for s in range(0, max_bone_set_index+1): + sums = weight_arrs[s].sum(axis=1) + if s == 0: + weight_total = sums + else: + weight_total += sums + + # Normalize weights so they sum to 1 + weight_total = weight_total.reshape(-1, 1) + for s in range(0, max_bone_set_index+1): + weight_arrs[s] /= weight_total + + weight = array_to_accessor( + weight_arrs[s], + component_type=gltf2_io_constants.ComponentType.Float, + data_type=gltf2_io_constants.DataType.Vec4, ) - attributes[weight_id] = weight + attributes[weight_id] = weight - bone_set_index += 1 - joint_id = 'JOINTS_' + str(bone_set_index) - weight_id = 'WEIGHTS_' + str(bone_set_index) return attributes -- cgit v1.2.3