From b42e4052b7b6472c72897a0239f964aea2b81b98 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Tue, 15 Jul 2025 20:16:47 -0300 Subject: [PATCH] Fix #121378: Can't snap parent to children with Affect Only Parent activated The flag that skips objects for snapping (`BA_SNAP_FIX_DEPS_FIASCO`) is set for all objects that have a `DEG_OB_COMP_TRANSFORM` relation. However, when the **Affect Only Parent** option is enabled, children are not transformed and therefore could still be snapped to. Despite this, the `DEG_OB_COMP_TRANSFORM` dependency remains present on them. To address this, a new callback was introduced that skips Transform-to-Transform dependencies while preserving Transform-to-Geometry dependencies in this scenario. This approach may introduce some false positives, leading to spurious dependency cycles (e.g., when constraints are involved). Nevertheless, the trade-off favors accepting these false positives rather than disabling the feature altogether. Also make non-functional change that just removes a flag before the snap loop, thus avoiding checking if the flag exists inside the loop. Ref !142007 --- .../transform/transform_convert_object.cc | 35 +++++++++++++++---- .../transform/transform_snap_object.cc | 4 +-- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/source/blender/editors/transform/transform_convert_object.cc b/source/blender/editors/transform/transform_convert_object.cc index 8a883a11bc2..2f7265c299e 100644 --- a/source/blender/editors/transform/transform_convert_object.cc +++ b/source/blender/editors/transform/transform_convert_object.cc @@ -311,7 +311,18 @@ static void trans_object_base_deps_flag_prepare(const TransInfo *t, } } -static void set_trans_object_base_deps_flag_cb(ID *id, eDepsObjectComponentType component) +static void tag_trans_objects_with_geometry_dep_only_fn(ID *id, eDepsObjectComponentType component) +{ + /* Here we only handle object IDs. */ + if (GS(id->name) != ID_OB) { + return; + } + if (component == DEG_OB_COMP_GEOMETRY) { + id->tag |= ID_TAG_DOIT; + } +} + +static void tag_trans_objects_dep_fn(ID *id, eDepsObjectComponentType component) { /* Here we only handle object IDs. */ if (GS(id->name) != ID_OB) { @@ -329,11 +340,21 @@ static void flush_trans_object_base_deps_flag(const TransInfo *t, Object *object return; } object->id.tag |= ID_TAG_DOIT; - DEG_foreach_dependent_ID_component(t->depsgraph, - &object->id, - DEG_OB_COMP_TRANSFORM, - DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS, - set_trans_object_base_deps_flag_cb); + + DEG_foreach_dependent_ID_component( + t->depsgraph, + &object->id, + DEG_OB_COMP_TRANSFORM, + DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS, + + /* When we transform parents while skipping children, we only traverse the GEOMETRY-dependent + * components. This avoids marking children as not participating in snapping but still marks + * objects with modifier dependencies. + * Unfortunately, some transform-dependent objects that are not children may also be skipped, + * such as constrained ones. + * See #121378 for details. */ + (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) ? tag_trans_objects_with_geometry_dep_only_fn : + tag_trans_objects_dep_fn); } static void trans_object_base_deps_flag_finish(const TransInfo *t, @@ -690,6 +711,7 @@ static void createTransObject(bContext *C, TransInfo *t) tdo->xcs, ob, ob_parent_recurse, object::XFORM_OB_SKIP_CHILD_PARENT_APPLY); BLI_ghash_insert(objects_parent_root, ob, ob_parent_recurse); base->flag_legacy |= BA_TRANSFORM_LOCKED_IN_PLACE; + base->flag_legacy &= ~BA_SNAP_FIX_DEPS_FIASCO; } } } @@ -711,6 +733,7 @@ static void createTransObject(bContext *C, TransInfo *t) object::object_xform_skip_child_container_item_ensure( tdo->xcs, ob, nullptr, object::XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM); base->flag_legacy |= BA_TRANSFORM_LOCKED_IN_PLACE; + base->flag_legacy &= ~BA_SNAP_FIX_DEPS_FIASCO; } else { Object *ob_parent_recurse = static_cast( diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc index 270aee09dac..d726fa279d7 100644 --- a/source/blender/editors/transform/transform_snap_object.cc +++ b/source/blender/editors/transform/transform_snap_object.cc @@ -409,9 +409,7 @@ static bool snap_object_is_snappable(const SnapObjectContext *sctx, return false; } - if ((snap_target_select == SCE_SNAP_TARGET_ALL) || - (base->flag_legacy & BA_TRANSFORM_LOCKED_IN_PLACE)) - { + if (snap_target_select == SCE_SNAP_TARGET_ALL) { return true; }