From 106cb51ab9ad26c473afa95440db3f2958af3599 Mon Sep 17 00:00:00 2001 From: Julien Duroure Date: Wed, 5 Oct 2022 10:07:58 +0200 Subject: glTF exporter: fix object parented to bones with own animation --- io_scene_gltf2/__init__.py | 2 +- .../exp/gltf2_blender_gather_animation_channels.py | 30 ++++++++++++++++++---- .../blender/exp/gltf2_blender_gather_animations.py | 2 +- .../blender/exp/gltf2_blender_gather_cache.py | 1 + 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/io_scene_gltf2/__init__.py b/io_scene_gltf2/__init__.py index 2a630e3f..8775084b 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, 4, 31), + "version": (3, 4, 32), 'blender': (3, 3, 0), 'location': 'File > Import-Export', 'description': 'Import-Export as glTF 2.0', 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 b872aeaa..33af9b3e 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 @@ -19,15 +19,35 @@ from io_scene_gltf2.blender.exp.gltf2_blender_gather_tree import VExportNode from . import gltf2_blender_export_keys -def gather_channels_baked(obj_uuid, export_settings): +def gather_channels_baked(obj_uuid, frame_range, export_settings): channels = [] # If no animation in file, no need to bake if len(bpy.data.actions) == 0: return None - start_frame = min([v[0] for v in [a.frame_range for a in bpy.data.actions]]) - end_frame = max([v[1] for v in [a.frame_range for a in bpy.data.actions]]) + blender_obj = export_settings['vtree'].nodes[obj_uuid].blender_object + + if frame_range is None: + start_frame = min([v[0] for v in [a.frame_range for a in bpy.data.actions]]) + end_frame = max([v[1] for v in [a.frame_range for a in bpy.data.actions]]) + else: + if blender_obj.animation_data and blender_obj.animation_data.action: + # Coming from object parented to bone, and object is also animated. So using range action + start_frame, end_frame = blender_obj.animation_data.action.frame_range[0], blender_obj.animation_data.action.frame_range[1] + else: + # Coming from object parented to bone, and object is not animated. So using range from armature + start_frame, end_frame = frame_range + + # use action if exists, else obj_uuid + # When an object need some forced baked, there are 2 situtations: + # - Non animated object, but there are some selection, so we need to bake + # - Object parented to bone. So we need to bake, because of inverse transforms on non default TRS armatures + # In this last case, there are 2 situations : + # - Object is also animated, so use the action name as key for caching + # - Object is not animated, so use obj_uuid as key for caching, like for non animated object (case 1) + + key_action = blender_obj.animation_data.action.name if blender_obj.animation_data and blender_obj.animation_data.action else obj_uuid for p in ["location", "rotation_quaternion", "scale"]: channel = gather_animation_channel( @@ -39,7 +59,7 @@ def gather_channels_baked(obj_uuid, export_settings): start_frame, end_frame, False, - obj_uuid, # Use obj uuid as action name for caching + key_action, # Use obj uuid as action name for caching (or action name if case of object parented to bone and animated) None, False #If Object is not animated, don't keep animation for this channel ) @@ -158,7 +178,7 @@ def gather_animation_channels(obj_uuid: int, children_obj_parent_to_bones.extend([child for child in export_settings['vtree'].nodes[bone_uuid].children if export_settings['vtree'].nodes[child].blender_type not in [VExportNode.BONE, VExportNode.ARMATURE]]) for child_uuid in children_obj_parent_to_bones: - channels_baked = gather_channels_baked(child_uuid, export_settings) + channels_baked = gather_channels_baked(child_uuid, (bake_range_start, bake_range_end), export_settings) if channels_baked is not None: channels.extend(channels_baked) diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animations.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animations.py index 7a6fd6c3..cf067e53 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_animations.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_animations.py @@ -41,7 +41,7 @@ def gather_animations( obj_uuid: int, # We also have to check if this is a skinned mesh, because we don't have to force animation baking on this case # (skinned meshes TRS must be ignored, says glTF specification) if export_settings['vtree'].nodes[obj_uuid].skin is None: - channels = gltf2_blender_gather_animation_channels.gather_channels_baked(obj_uuid, export_settings) + channels = gltf2_blender_gather_animation_channels.gather_channels_baked(obj_uuid, None, export_settings) if channels is not None: animation = gltf2_io.Animation( channels=channels, diff --git a/io_scene_gltf2/blender/exp/gltf2_blender_gather_cache.py b/io_scene_gltf2/blender/exp/gltf2_blender_gather_cache.py index 3539b968..4ca7cdf5 100755 --- a/io_scene_gltf2/blender/exp/gltf2_blender_gather_cache.py +++ b/io_scene_gltf2/blender/exp/gltf2_blender_gather_cache.py @@ -89,6 +89,7 @@ def objectcache(func): if cache_key_args[0] not in func.__objectcache.keys(): result = func(*args) func.__objectcache = result + # Here are the key used: result[obj_uuid][action_name][frame] return result[cache_key_args[0]][cache_key_args[1]][cache_key_args[4]] # object is in cache, but not this action # We need to keep other actions -- cgit v1.2.3