From 6212c3c37407d9dadc00a922242f06cbd5ee93b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Mon, 13 May 2024 12:41:14 +0200 Subject: [PATCH] Fix #121161: Regression: Frame Selected Includes Hidden Bones Refactor `BKE_armature_min_max()` so that it calls `BKE_pose_minmax(ob, use_hidden=false)`. The former took neither bone visibility nor custom bone shapes into account when computing the bounding box. Now these two are unified, fixing the regression. `BKE_armature_min_max()` is now basically a thin wrapper that uses more modern C++ types in its signature. This will be cleaned up in a follow-up refactor commit. Another difference is that these functions return the AABB in different coordinate spaces (object vs. world). This isn't done entirely correctly (just transforming the two extreme points), but in a way that is symmetrical with `BKE_object_minmax()`. Pull Request: https://projects.blender.org/blender/blender/pulls/121739 --- source/blender/blenkernel/BKE_armature.hh | 5 +++- source/blender/blenkernel/intern/armature.cc | 23 +++++++++++-------- source/blender/blenkernel/intern/object.cc | 2 +- .../transform_snap_object_armature.cc | 3 +-- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/source/blender/blenkernel/BKE_armature.hh b/source/blender/blenkernel/BKE_armature.hh index 7df93c38b70..62061e8684e 100644 --- a/source/blender/blenkernel/BKE_armature.hh +++ b/source/blender/blenkernel/BKE_armature.hh @@ -155,7 +155,10 @@ void BKE_armature_copy_bone_transforms(bArmature *armature_dst, const bArmature void BKE_armature_transform(bArmature *arm, const float mat[4][4], bool do_props); -std::optional> BKE_armature_min_max(const bPose *pose); +/** + * Return the posed Armature bounding box in object-local coordinate space. + */ +std::optional> BKE_armature_min_max(const Object *ob); /** * Calculate the axis-aligned bounds of `pchan` in world-space, diff --git a/source/blender/blenkernel/intern/armature.cc b/source/blender/blenkernel/intern/armature.cc index a5d28c6b92e..2da4971837c 100644 --- a/source/blender/blenkernel/intern/armature.cc +++ b/source/blender/blenkernel/intern/armature.cc @@ -22,6 +22,7 @@ #include "BLI_listbase.h" #include "BLI_math_geom.h" #include "BLI_math_matrix.h" +#include "BLI_math_matrix.hh" #include "BLI_math_rotation.h" #include "BLI_math_vector.h" #include "BLI_span.hh" @@ -3020,21 +3021,23 @@ void BKE_pose_where_is(Depsgraph *depsgraph, Scene *scene, Object *ob) /** \name Calculate Bounding Box (Armature & Pose) * \{ */ -std::optional> BKE_armature_min_max(const bPose *pose) +std::optional> BKE_armature_min_max(const Object *ob) { - if (BLI_listbase_is_empty(&pose->chanbase)) { - return std::nullopt; - } + BLI_assert(ob->data); + BLI_assert(ob->type == OB_ARMATURE); + BLI_assert(GS(static_cast(ob->data)->name) == ID_AR); + blender::float3 min(std::numeric_limits::max()); blender::float3 max(std::numeric_limits::lowest()); - /* For now, we assume BKE_pose_where_is has already been called - * (hence we have valid data in pachan). */ - LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) { - minmax_v3v3_v3(min, max, pchan->pose_head); - minmax_v3v3_v3(min, max, pchan->pose_tail); + + const bool has_minmax = BKE_pose_minmax(ob, &min[0], &max[0], false, false); + + if (!has_minmax) { + return std::nullopt; } - return blender::Bounds{min, max}; + return blender::Bounds{math::transform_point(ob->world_to_object(), min), + math::transform_point(ob->world_to_object(), max)}; } void BKE_pchan_minmax(const Object *ob, diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 49bb0c0bea0..0e25e24974c 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -3569,7 +3569,7 @@ std::optional> BKE_object_boundbox_get(const Ob case OB_LATTICE: return BKE_lattice_minmax(static_cast(ob->data)); case OB_ARMATURE: - return BKE_armature_min_max(ob->pose); + return BKE_armature_min_max(ob); case OB_GPENCIL_LEGACY: return BKE_gpencil_data_minmax(static_cast(ob->data)); case OB_CURVES: diff --git a/source/blender/editors/transform/transform_snap_object_armature.cc b/source/blender/editors/transform/transform_snap_object_armature.cc index e26e3837f51..9947c941f58 100644 --- a/source/blender/editors/transform/transform_snap_object_armature.cc +++ b/source/blender/editors/transform/transform_snap_object_armature.cc @@ -39,8 +39,7 @@ eSnapMode snapArmature(SnapObjectContext *sctx, const bool is_editmode = arm->edbo != nullptr; if (is_editmode == false) { - const std::optional> bounds = BKE_armature_min_max( - ob_eval->pose); + const std::optional> bounds = BKE_armature_min_max(ob_eval); if (bounds && !nearest2d.snap_boundbox(bounds->min, bounds->max)) { return retval; }