From fc320ea236c7f264a1438e7af338581a37bb74b1 Mon Sep 17 00:00:00 2001 From: Julien Duroure Date: Fri, 23 Aug 2019 07:29:41 +0200 Subject: glTF exporter: fix shapekeys animation export Animation channels must be sorted in exactly same order than shapekeys --- io_scene_gltf2/__init__.py | 2 +- .../blender/exp/gltf2_blender_extract.py | 12 +- .../exp/gltf2_blender_gather_animation_channels.py | 34 ++++- .../blender/exp/gltf2_blender_gather_mesh.py | 6 +- .../blender/exp/gltf2_blender_gather_primitives.py | 138 +++++++++++---------- 5 files changed, 113 insertions(+), 79 deletions(-) diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py index b38eaf82..a020e0eb 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": (0, 9, 48), + "version": (0, 9, 49), 'blender': (2, 80, 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 7adda5a4..a4705e91 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_extract.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_extract.py @@ -499,14 +499,14 @@ def extract_primitives(glTF, blender_mesh, blender_vertex_groups, modifiers, exp blender_shape_keys = [] if blender_mesh.shape_keys is not None: - morph_max = len(blender_mesh.shape_keys.key_blocks) - 1 - for blender_shape_key in blender_mesh.shape_keys.key_blocks: if blender_shape_key != blender_shape_key.relative_key: - blender_shape_keys.append(ShapeKey( - blender_shape_key, - blender_shape_key.normals_vertex_get(), # calculate vertex normals for this shape key - blender_shape_key.normals_polygon_get())) # calculate polygon normals for this shape key + if blender_shape_key.mute is False: + morph_max += 1 + blender_shape_keys.append(ShapeKey( + blender_shape_key, + blender_shape_key.normals_vertex_get(), # calculate vertex normals for this shape key + blender_shape_key.normals_polygon_get())) # calculate polygon normals for this shape key # # Convert polygon to primitive indices and eliminate invalid ones. Assign to material. diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channels.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channels.py index 412f275b..45a75717 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channels.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animation_channels.py @@ -64,12 +64,35 @@ def gather_animation_channels(blender_action: bpy.types.Action, channels.append(channel) else: for channel_group in __get_channel_groups(blender_action, blender_object, export_settings): - channel = __gather_animation_channel(channel_group, blender_object, export_settings, None, None, None, None, blender_action.name) + channel_group_sorted = __get_channel_group_sorted(channel_group, blender_object) + channel = __gather_animation_channel(channel_group_sorted, blender_object, export_settings, None, None, None, None, blender_action.name) if channel is not None: channels.append(channel) return channels +def __get_channel_group_sorted(channels: typing.Tuple[bpy.types.FCurve], blender_object: bpy.types.Object): + # if this is shapekey animation, we need to sort in same order than shapekeys + # else, no need to sort + if blender_object.type == "MESH": + first_channel = channels[0] + object_path = get_target_object_path(first_channel.data_path) + if object_path: + # This is shapekeys, we need to sort channels + shapekeys_idx = {} + cpt_sk = 0 + for sk in blender_object.data.shape_keys.key_blocks: + if sk == sk.relative_key: + continue + if sk.mute is True: + continue + shapekeys_idx[sk.name] = cpt_sk + cpt_sk += 1 + + return tuple(sorted(channels, key=lambda x: shapekeys_idx[blender_object.data.shape_keys.path_resolve(get_target_object_path(x.data_path)).name])) + + # if not shapekeys, stay in same order, because order doesn't matter + return channels def __gather_animation_channel(channels: typing.Tuple[bpy.types.FCurve], blender_object: bpy.types.Object, @@ -164,12 +187,17 @@ def __get_channel_groups(blender_action: bpy.types.Action, blender_object: bpy.t else: try: target = gltf2_blender_get.get_object_from_datapath(blender_object, object_path) + if blender_object.type == "MESH": + shape_key = blender_object.data.shape_keys.path_resolve(object_path) + if shape_key.mute is True: + continue except ValueError as e: # if the object is a mesh and the action target path can not be resolved, we know that this is a morph # animation. if blender_object.type == "MESH": - # if you need the specific shape key for some reason, this is it: - # shape_key = blender_object.data.shape_keys.path_resolve(object_path) + shape_key = blender_object.data.shape_keys.path_resolve(object_path) + if shape_key.mute is True: + continue target = blender_object.data.shape_keys else: gltf2_io_debug.print_console("WARNING", "Animation target {} not found".format(object_path)) diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_mesh.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_mesh.py index e321ea07..d0d2d4a5 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_mesh.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_mesh.py @@ -83,7 +83,8 @@ def __gather_extras(blender_mesh: bpy.types.Mesh, target_names = [] for blender_shape_key in blender_mesh.shape_keys.key_blocks: if blender_shape_key != blender_shape_key.relative_key: - target_names.append(blender_shape_key.name) + if blender_shape_key.mute is False: + target_names.append(blender_shape_key.name) extras['targetNames'] = target_names if extras: @@ -130,7 +131,8 @@ def __gather_weights(blender_mesh: bpy.types.Mesh, for blender_shape_key in blender_mesh.shape_keys.key_blocks: if blender_shape_key != blender_shape_key.relative_key: - weights.append(blender_shape_key.value) + if blender_shape_key.mute is False: + weights.append(blender_shape_key.value) return weights diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_primitives.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_primitives.py index 2c4ee91f..82673e5e 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_primitives.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_primitives.py @@ -143,87 +143,91 @@ def __gather_targets(blender_primitive, blender_mesh, modifiers, export_settings if blender_mesh.shape_keys is not None: morph_index = 0 for blender_shape_key in blender_mesh.shape_keys.key_blocks: - if blender_shape_key != blender_shape_key.relative_key: - - target_position_id = 'MORPH_POSITION_' + str(morph_index) - target_normal_id = 'MORPH_NORMAL_' + str(morph_index) - target_tangent_id = 'MORPH_TANGENT_' + str(morph_index) - - if blender_primitive["attributes"].get(target_position_id): - target = {} - internal_target_position = blender_primitive["attributes"][target_position_id] + if blender_shape_key == blender_shape_key.relative_key: + continue + + if blender_shape_key.mute is True: + continue + + target_position_id = 'MORPH_POSITION_' + str(morph_index) + target_normal_id = 'MORPH_NORMAL_' + str(morph_index) + target_tangent_id = 'MORPH_TANGENT_' + str(morph_index) + + if blender_primitive["attributes"].get(target_position_id): + target = {} + internal_target_position = blender_primitive["attributes"][target_position_id] + binary_data = gltf2_io_binary_data.BinaryData.from_list( + internal_target_position, + gltf2_io_constants.ComponentType.Float + ) + target["POSITION"] = gltf2_io.Accessor( + buffer_view=binary_data, + byte_offset=None, + component_type=gltf2_io_constants.ComponentType.Float, + count=len(internal_target_position) // gltf2_io_constants.DataType.num_elements( + gltf2_io_constants.DataType.Vec3), + extensions=None, + extras=None, + max=gltf2_blender_utils.max_components( + internal_target_position, gltf2_io_constants.DataType.Vec3), + min=gltf2_blender_utils.min_components( + internal_target_position, gltf2_io_constants.DataType.Vec3), + name=None, + normalized=None, + sparse=None, + type=gltf2_io_constants.DataType.Vec3 + ) + + if export_settings[NORMALS] \ + and export_settings[MORPH_NORMAL] \ + and blender_primitive["attributes"].get(target_normal_id): + + internal_target_normal = blender_primitive["attributes"][target_normal_id] binary_data = gltf2_io_binary_data.BinaryData.from_list( - internal_target_position, - gltf2_io_constants.ComponentType.Float + internal_target_normal, + gltf2_io_constants.ComponentType.Float, ) - target["POSITION"] = gltf2_io.Accessor( + target['NORMAL'] = gltf2_io.Accessor( buffer_view=binary_data, byte_offset=None, component_type=gltf2_io_constants.ComponentType.Float, - count=len(internal_target_position) // gltf2_io_constants.DataType.num_elements( + count=len(internal_target_normal) // gltf2_io_constants.DataType.num_elements( gltf2_io_constants.DataType.Vec3), extensions=None, extras=None, - max=gltf2_blender_utils.max_components( - internal_target_position, gltf2_io_constants.DataType.Vec3), - min=gltf2_blender_utils.min_components( - internal_target_position, gltf2_io_constants.DataType.Vec3), + max=None, + min=None, name=None, normalized=None, sparse=None, type=gltf2_io_constants.DataType.Vec3 ) - if export_settings[NORMALS] \ - and export_settings[MORPH_NORMAL] \ - and blender_primitive["attributes"].get(target_normal_id): - - internal_target_normal = blender_primitive["attributes"][target_normal_id] - binary_data = gltf2_io_binary_data.BinaryData.from_list( - internal_target_normal, - gltf2_io_constants.ComponentType.Float, - ) - target['NORMAL'] = gltf2_io.Accessor( - buffer_view=binary_data, - byte_offset=None, - component_type=gltf2_io_constants.ComponentType.Float, - count=len(internal_target_normal) // gltf2_io_constants.DataType.num_elements( - gltf2_io_constants.DataType.Vec3), - extensions=None, - extras=None, - max=None, - min=None, - name=None, - normalized=None, - sparse=None, - type=gltf2_io_constants.DataType.Vec3 - ) - - if export_settings[TANGENTS] \ - and export_settings[MORPH_TANGENT] \ - and blender_primitive["attributes"].get(target_tangent_id): - internal_target_tangent = blender_primitive["attributes"][target_tangent_id] - binary_data = gltf2_io_binary_data.BinaryData.from_list( - internal_target_tangent, - gltf2_io_constants.ComponentType.Float, - ) - target['TANGENT'] = gltf2_io.Accessor( - buffer_view=binary_data, - byte_offset=None, - component_type=gltf2_io_constants.ComponentType.Float, - count=len(internal_target_tangent) // gltf2_io_constants.DataType.num_elements( - gltf2_io_constants.DataType.Vec3), - extensions=None, - extras=None, - max=None, - min=None, - name=None, - normalized=None, - sparse=None, - type=gltf2_io_constants.DataType.Vec3 - ) - targets.append(target) - morph_index += 1 + if export_settings[TANGENTS] \ + and export_settings[MORPH_TANGENT] \ + and blender_primitive["attributes"].get(target_tangent_id): + internal_target_tangent = blender_primitive["attributes"][target_tangent_id] + binary_data = gltf2_io_binary_data.BinaryData.from_list( + internal_target_tangent, + gltf2_io_constants.ComponentType.Float, + ) + target['TANGENT'] = gltf2_io.Accessor( + buffer_view=binary_data, + byte_offset=None, + component_type=gltf2_io_constants.ComponentType.Float, + count=len(internal_target_tangent) // gltf2_io_constants.DataType.num_elements( + gltf2_io_constants.DataType.Vec3), + extensions=None, + extras=None, + max=None, + min=None, + name=None, + normalized=None, + sparse=None, + type=gltf2_io_constants.DataType.Vec3 + ) + targets.append(target) + morph_index += 1 return targets return None -- cgit v1.2.3