[Bf-blender-cvs] [908b383b7d2] blender-v2.92-release: UV: tweak face select behavior

Campbell Barton noreply at git.blender.org
Wed Jan 20 07:08:29 CET 2021


Commit: 908b383b7d2199c0c614d085ff65a03eb7852274
Author: Campbell Barton
Date:   Wed Jan 20 16:57:02 2021 +1100
Branches: blender-v2.92-release
https://developer.blender.org/rB908b383b7d2199c0c614d085ff65a03eb7852274

UV: tweak face select behavior

When the mouse cursor is inside the UV face,
extend the selection threshold.

This means when zoomed in, a face can always be selected when the cursor
is inside it.
In the case of multiple overlapping faces - the face with the closest
center is used.

----

Prior to 246efd7286f6187e4dd4b3edcc79cccb1746bb1d, the UV selection
threshold was scaled by the zoom level, so selecting a face when zoomed
in close would often often select faces even when the on-screen center
was outside the intended threshold.

Having a zoom-independent threshold may require more precision than
users are used to.

This change addresses this.

===================================================================

M	source/blender/editors/uvedit/uvedit_intern.h
M	source/blender/editors/uvedit/uvedit_select.c

===================================================================

diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 45d65e7070e..cd8fbd00316 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -93,10 +93,21 @@ bool uv_find_nearest_edge_multi(struct Scene *scene,
                                 const float co[2],
                                 struct UvNearestHit *hit);
 
+bool uv_find_nearest_face_ex(struct Scene *scene,
+                             struct Object *obedit,
+                             const float co[2],
+                             struct UvNearestHit *hit,
+                             const bool only_in_face);
 bool uv_find_nearest_face(struct Scene *scene,
                           struct Object *obedit,
                           const float co[2],
                           struct UvNearestHit *hit);
+bool uv_find_nearest_face_multi_ex(struct Scene *scene,
+                                   struct Object **objects,
+                                   const uint objects_len,
+                                   const float co[2],
+                                   struct UvNearestHit *hit,
+                                   const bool only_in_face);
 bool uv_find_nearest_face_multi(struct Scene *scene,
                                 struct Object **objects,
                                 const uint objects_len,
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
index 394bdd14166..c69900678db 100644
--- a/source/blender/editors/uvedit/uvedit_select.c
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -719,7 +719,17 @@ bool uv_find_nearest_edge_multi(
   return found;
 }
 
-bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit)
+/**
+ * \param only_in_face: when true, only hit faces which `co` is inside.
+ * This gives users a result they might expect, especially when zoomed in.
+ *
+ * \note Concave faces can cause odd behavior, although in practice this isn't often an issue.
+ * The center can be outside the face, in this case the distance to the center
+ * could cause the face to be considered too far away.
+ * If this becomes an issue we could track the distance to the faces closest edge.
+ */
+bool uv_find_nearest_face_ex(
+    Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit, const bool only_in_face)
 {
   BLI_assert((hit->scale[0] > 0.0f) && (hit->scale[1] > 0.0f));
   BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -745,6 +755,13 @@ bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNea
     const float dist_test_sq = len_squared_v2(delta);
 
     if (dist_test_sq < hit->dist_sq) {
+
+      if (only_in_face) {
+        if (!BM_face_uv_point_inside_test(efa, co, cd_loop_uv_offset)) {
+          continue;
+        }
+      }
+
       hit->ob = obedit;
       hit->efa = efa;
       hit->dist_sq = dist_test_sq;
@@ -754,19 +771,34 @@ bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNea
   return found;
 }
 
-bool uv_find_nearest_face_multi(
-    Scene *scene, Object **objects, const uint objects_len, const float co[2], UvNearestHit *hit)
+bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit)
+{
+  return uv_find_nearest_face_ex(scene, obedit, co, hit, NULL);
+}
+
+bool uv_find_nearest_face_multi_ex(Scene *scene,
+                                   Object **objects,
+                                   const uint objects_len,
+                                   const float co[2],
+                                   UvNearestHit *hit,
+                                   const bool only_in_face)
 {
   bool found = false;
   for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
     Object *obedit = objects[ob_index];
-    if (uv_find_nearest_face(scene, obedit, co, hit)) {
+    if (uv_find_nearest_face_ex(scene, obedit, co, hit, only_in_face)) {
       found = true;
     }
   }
   return found;
 }
 
+bool uv_find_nearest_face_multi(
+    Scene *scene, Object **objects, const uint objects_len, const float co[2], UvNearestHit *hit)
+{
+  return uv_find_nearest_face_multi_ex(scene, objects, objects_len, co, hit, false);
+}
+
 static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset)
 {
   const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv;
@@ -1934,6 +1966,15 @@ static int uv_mouse_select_multi(bContext *C,
   else if (selectmode == UV_SELECT_FACE) {
     /* find face */
     found_item = uv_find_nearest_face_multi(scene, objects, objects_len, co, &hit);
+
+    if (!found_item) {
+      /* Fallback, perform a second pass without a limited threshold,
+       * which succeeds as long as the cursor is inside the UV face.
+       * Useful when zoomed in, to select faces with distant screen-space face centers. */
+      hit.dist_sq = FLT_MAX;
+      found_item = uv_find_nearest_face_multi_ex(scene, objects, objects_len, co, &hit, true);
+    }
+
     if (found_item) {
       BMesh *bm = BKE_editmesh_from_object(hit.ob)->bm;
       BM_mesh_active_face_set(bm, hit.efa);



More information about the Bf-blender-cvs mailing list