From 6325f33dd9e260d9c0de2641baf30f54c25a0f90 Mon Sep 17 00:00:00 2001 From: Thomas Barlow Date: Thu, 7 Sep 2023 20:41:16 +0100 Subject: [PATCH 1/3] Fix #104875: Animated object instances export frozen in place It seems to have been a mistake in 2bfab056d2 that prevented the matrices of dupli instances being updated while iterating through each frame. --- io_scene_fbx/export_fbx_bin.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/io_scene_fbx/export_fbx_bin.py b/io_scene_fbx/export_fbx_bin.py index a6a04a7bb..400b6405c 100644 --- a/io_scene_fbx/export_fbx_bin.py +++ b/io_scene_fbx/export_fbx_bin.py @@ -2249,13 +2249,31 @@ def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=No force_sek, (cam.dof.focus_distance,)) animdata_cameras[cam_key] = (acnode_lens, acnode_focus_distance, cam) + # Find all animated objects that have dupli instances, so that `depsgraph.object_instances` only has to be iterated + # at most once per frame. + original_parents_with_duplis = set() + for ob_obj in animdata_ob: + for dp_obj in ob_obj.dupli_list_gen(depsgraph): + if dp_obj in objects: + original_parents_with_duplis.add(ob_obj.bdata) + break + has_animated_duplis = bool(original_parents_with_duplis) + currframe = f_start while currframe <= f_end: real_currframe = currframe - f_start if start_zero else currframe scene.frame_set(int(currframe), subframe=currframe - int(currframe)) - for dp_obj in ob_obj.dupli_list_gen(depsgraph): - pass # Merely updating dupli matrix of ObjectWrapper... + if has_animated_duplis: + # Changing the scene's frame invalidates existing dupli instances. To get the updated matrices of duplis for + # this frame, we must get the duplis from the depsgraph again. + for dup in depsgraph.object_instances: + # This condition matches the condition for duplis to be returned by ObjectWrapper.dupli_list_gen, which + # was used to populate original_parents_with_duplis. + if (parent := dup.parent) and parent.original in original_parents_with_duplis: + # ObjectWrapper caches its instances. Creating a new instance updates the existing instance with the + # current frame's matrix. + ObjectWrapper(dup) for ob_obj, (anim_loc, anim_rot, anim_scale) in animdata_ob.items(): # We compute baked loc/rot/scale for all objects (rot being euler-compat with previous value!). p_rot = p_rots.get(ob_obj, None) -- 2.30.2 From b76c9ec89f7987c91c2d0d950a7625a9d31a4f21 Mon Sep 17 00:00:00 2001 From: Thomas Barlow Date: Thu, 7 Sep 2023 23:16:59 +0100 Subject: [PATCH 2/3] Simpler, more robust set comprehension Will work even if scene_data.objects contains duplis without their parent object --- io_scene_fbx/export_fbx_bin.py | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/io_scene_fbx/export_fbx_bin.py b/io_scene_fbx/export_fbx_bin.py index 400b6405c..2b2a393f5 100644 --- a/io_scene_fbx/export_fbx_bin.py +++ b/io_scene_fbx/export_fbx_bin.py @@ -2249,15 +2249,10 @@ def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=No force_sek, (cam.dof.focus_distance,)) animdata_cameras[cam_key] = (acnode_lens, acnode_focus_distance, cam) - # Find all animated objects that have dupli instances, so that `depsgraph.object_instances` only has to be iterated - # at most once per frame. - original_parents_with_duplis = set() - for ob_obj in animdata_ob: - for dp_obj in ob_obj.dupli_list_gen(depsgraph): - if dp_obj in objects: - original_parents_with_duplis.add(ob_obj.bdata) - break - has_animated_duplis = bool(original_parents_with_duplis) + # Get all parent bdata of animated dupli instances, so that we can quickly identify which instances in + # `depsgraph.object_instances` are animated and need their ObjectWrappers' matrices updated each frame. + dupli_parent_bdata = {dup.get_parent().bdata for dup in animdata_ob if dup.is_dupli} + has_animated_duplis = bool(dupli_parent_bdata) currframe = f_start while currframe <= f_end: @@ -2268,11 +2263,9 @@ def fbx_animations_do(scene_data, ref_id, f_start, f_end, start_zero, objects=No # Changing the scene's frame invalidates existing dupli instances. To get the updated matrices of duplis for # this frame, we must get the duplis from the depsgraph again. for dup in depsgraph.object_instances: - # This condition matches the condition for duplis to be returned by ObjectWrapper.dupli_list_gen, which - # was used to populate original_parents_with_duplis. - if (parent := dup.parent) and parent.original in original_parents_with_duplis: - # ObjectWrapper caches its instances. Creating a new instance updates the existing instance with the - # current frame's matrix. + if (parent := dup.parent) and parent.original in dupli_parent_bdata: + # ObjectWrapper caches its instances. Attempting to create a new instance updates the existing + # ObjectWrapper instance with the current frame's matrix and then returns the existing instance. ObjectWrapper(dup) for ob_obj, (anim_loc, anim_rot, anim_scale) in animdata_ob.items(): # We compute baked loc/rot/scale for all objects (rot being euler-compat with previous value!). -- 2.30.2 From a87faacfff0b11a77015fd9f56863cb3fcc81eed Mon Sep 17 00:00:00 2001 From: Thomas Barlow Date: Mon, 11 Sep 2023 16:21:35 +0100 Subject: [PATCH 3/3] Increase FBX IO version --- io_scene_fbx/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io_scene_fbx/__init__.py b/io_scene_fbx/__init__.py index 00243d5c1..590c792da 100644 --- a/io_scene_fbx/__init__.py +++ b/io_scene_fbx/__init__.py @@ -5,7 +5,7 @@ bl_info = { "name": "FBX format", "author": "Campbell Barton, Bastien Montagne, Jens Restemeier, @Mysteryem", - "version": (5, 7, 3), + "version": (5, 7, 4), "blender": (3, 6, 0), "location": "File > Import-Export", "description": "FBX IO meshes, UVs, vertex colors, materials, textures, cameras, lamps and actions", -- 2.30.2