From fb2548afbdc36d7df20aa82d2a3f0e7c1eb1fdfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Tue, 30 Sep 2025 15:06:50 +0200 Subject: [PATCH] Revert "IO: update FBX im-/exporter to use the current Action API" This reverts commit 8536cd794e87a4af7c8f77a0a69afdcc76fa91c9. It is still under review, and was accidentally pushed to `main`. --- .../io_scene_fbx/export_fbx_bin.py | 39 ++++++------------- .../addons_core/io_scene_fbx/import_fbx.py | 10 ++--- 2 files changed, 15 insertions(+), 34 deletions(-) diff --git a/scripts/addons_core/io_scene_fbx/export_fbx_bin.py b/scripts/addons_core/io_scene_fbx/export_fbx_bin.py index 7f1e6bfea71..4641368ffb2 100644 --- a/scripts/addons_core/io_scene_fbx/export_fbx_bin.py +++ b/scripts/addons_core/io_scene_fbx/export_fbx_bin.py @@ -2491,25 +2491,16 @@ def fbx_animations(scene_data): # All actions. if scene_data.settings.bake_anim_use_all_actions: - def find_validate_action_slot(act, path_resolve) -> bpy.types.ActionSlot | None: - for layer in act.layers: - for strip in layer.strips: - for channelbag in strip.channelbags: - if not channelbag.fcurves: - # Do not export empty Channelbags. - continue - for fc in channelbag.fcurves: - data_path = fc.data_path - if fc.array_index: - data_path = data_path + "[%d]" % fc.array_index - try: - path_resolve(data_path) - except ValueError: - break # Invalid, go to next strip. - else: - # Did not 'break', so all F-Curves are valid. - return channelbag.slot - return None # Found nothing to return. + def validate_actions(act, path_resolve): + for fc in act.fcurves: + data_path = fc.data_path + if fc.array_index: + data_path = data_path + "[%d]" % fc.array_index + try: + path_resolve(data_path) + except ValueError: + return False # Invalid. + return True # Valid. def restore_object(ob_to, ob_from): # Restore org state of object (ugh :/ ). @@ -2549,20 +2540,14 @@ def fbx_animations(scene_data): pbones_matrices = [pbo.matrix_basis.copy() for pbo in ob.pose.bones] if ob.type == 'ARMATURE' else ... org_act = ob.animation_data.action - org_act_slot = ob.animation_data.action_slot path_resolve = ob.path_resolve for act in bpy.data.actions: # For now, *all* paths in the action must be valid for the object, to validate the action. # Unless that action was already assigned to the object! - if act == org_act: - act_slot = org_act_slot - else: - act_slot = find_validate_action_slot(act, path_resolve) - if not act_slot: + if act != org_act and not validate_actions(act, path_resolve): continue ob.animation_data.action = act - ob.animation_data.action_slot = act_slot frame_start, frame_end = act.frame_range # sic! add_anim(animations, animated, fbx_animations_do(scene_data, (ob, act), frame_start, frame_end, True, @@ -2572,7 +2557,6 @@ def fbx_animations(scene_data): for pbo, mat in zip(ob.pose.bones, pbones_matrices): pbo.matrix_basis = mat.copy() ob.animation_data.action = org_act - ob.animation_data.action_slot = org_act_slot restore_object(ob, ob_copy) scene.frame_set(scene.frame_current, subframe=0.0) @@ -2580,7 +2564,6 @@ def fbx_animations(scene_data): for pbo, mat in zip(ob.pose.bones, pbones_matrices): pbo.matrix_basis = mat.copy() ob.animation_data.action = org_act - ob.animation_data.action_slot = org_act_slot bpy.data.objects.remove(ob_copy) scene.frame_set(scene.frame_current, subframe=0.0) diff --git a/scripts/addons_core/io_scene_fbx/import_fbx.py b/scripts/addons_core/io_scene_fbx/import_fbx.py index b48a2456e75..e86a781527d 100644 --- a/scripts/addons_core/io_scene_fbx/import_fbx.py +++ b/scripts/addons_core/io_scene_fbx/import_fbx.py @@ -17,7 +17,6 @@ if "bpy" in locals(): import bpy from bpy.app.translations import pgettext_tip as tip_ from mathutils import Matrix, Euler, Vector, Quaternion -from bpy_extras import anim_utils # Also imported in .fbx_utils, so importing here is unlikely to further affect Blender startup time. import numpy as np @@ -894,10 +893,10 @@ def blen_store_keyframes_multi(fbx_key_times, fcurve_and_key_values_pairs, blen_ blen_fcurve.update() -def blen_read_animations_action_item(channelbag, item, cnodes, fps, anim_offset, global_scale, shape_key_deforms, +def blen_read_animations_action_item(action, item, cnodes, fps, anim_offset, global_scale, shape_key_deforms, fbx_ktime): """ - 'Bake' loc/rot/scale into the channelbag, + 'Bake' loc/rot/scale into the action, taking any pre_ and post_ matrix into account to transform from fbx into blender space. """ from bpy.types import ShapeKey, Material, Camera @@ -949,7 +948,7 @@ def blen_read_animations_action_item(channelbag, item, cnodes, fps, anim_offset, else: # Euler props[1] = (bl_obj.path_from_id("rotation_euler"), 3, grpname or "Euler Rotation") - blen_curves = [channelbag.fcurves.new(prop, index=channel, group_name=grpname) + blen_curves = [action.fcurves.new(prop, index=channel, action_group=grpname) for prop, nbr_channels, grpname in props for channel in range(nbr_channels)] if isinstance(item, Material): @@ -1116,8 +1115,7 @@ def blen_read_animations(fbx_tmpl_astack, fbx_tmpl_alayer, stacks, scene, anim_o id_data.animation_data.action_slot = action.slots[0] # And actually populate the action! - channelbag = anim_utils.action_ensure_channelbag_for_slot(action, action.slots[0]) - blen_read_animations_action_item(channelbag, item, cnodes, scene.render.fps, anim_offset, global_scale, + blen_read_animations_action_item(action, item, cnodes, scene.render.fps, anim_offset, global_scale, shape_key_values, fbx_ktime) # If the minimum/maximum animated value is outside the slider range of the shape key, attempt to expand the slider