Transform: use a threshold for UV snapping

Unlike 3Dview snapping, UV snapping is always done to the UV closest to
the mouse cursor, no matter the distance.

From the user's point of view, this appears to be an inconsistency (See
{T93538}).

Therefore, set a minimum distance for snapping and, as in 3D View and
highlight the snap with a drawing of a circle.

Release Note: https://wiki.blender.org/wiki/Reference/Release_Notes/3.3/Modeling

Reviewed By: #uv_editing, campbellbarton

Maniphest Tasks: T93538

Differential Revision: https://developer.blender.org/D13873
This commit is contained in:
Germano Cavalcante 2022-05-03 10:09:22 -03:00 committed by Germano Cavalcante
parent 08daeb9472
commit d2271cf939
Notes: blender-bot 2023-02-14 03:03:03 +01:00
Referenced by commit 0c8de0eb3b, Fix T100632: Regression: Node border snap guide line not drawing properly
Referenced by commit 046b45749c, Fix cursor snap not acting on selected UVs
Referenced by issue #100632, Regression: Node border snap guide line not drawing properly
Referenced by issue #93538, UV Snapping behaviour inconsistency
3 changed files with 72 additions and 31 deletions

View File

@ -24,6 +24,7 @@ struct Object;
struct Scene;
struct SpaceImage;
struct ToolSettings;
struct View2D;
struct ViewLayer;
struct bContext;
struct bNode;
@ -242,15 +243,12 @@ void uvedit_deselect_flush(const struct Scene *scene, struct BMEditMesh *em);
*/
void uvedit_select_flush(const struct Scene *scene, struct BMEditMesh *em);
bool ED_uvedit_nearest_uv(const struct Scene *scene,
struct Object *obedit,
const float co[2],
float *dist_sq,
float r_uv[2]);
bool ED_uvedit_nearest_uv_multi(const struct Scene *scene,
bool ED_uvedit_nearest_uv_multi(const struct View2D *v2d,
const struct Scene *scene,
struct Object **objects,
uint objects_len,
const float co[2],
const int mval[2],
const bool ignore_selected,
float *dist_sq,
float r_uv[2]);

View File

@ -15,6 +15,7 @@
#include "BLI_math.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
#include "BKE_context.h"
@ -25,6 +26,7 @@
#include "RNA_access.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_gizmo_library.h"
@ -173,20 +175,20 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
return;
}
UI_GetThemeColor3ubv(TH_TRANSFORM, col);
col[3] = 128;
UI_GetThemeColor3ubv(TH_SELECT, selectedCol);
selectedCol[3] = 128;
UI_GetThemeColor3ubv(TH_ACTIVE, activeCol);
activeCol[3] = 192;
if (t->spacetype == SPACE_VIEW3D) {
bool draw_target = (t->tsnap.status & TARGET_INIT) &&
(t->tsnap.mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR);
if (draw_target || validSnap(t)) {
UI_GetThemeColor3ubv(TH_TRANSFORM, col);
col[3] = 128;
UI_GetThemeColor3ubv(TH_SELECT, selectedCol);
selectedCol[3] = 128;
UI_GetThemeColor3ubv(TH_ACTIVE, activeCol);
activeCol[3] = 192;
const float *loc_cur = NULL;
const float *loc_prev = NULL;
const float *normal = NULL;
@ -240,8 +242,26 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_IMAGE) {
if (validSnap(t)) {
/* This will not draw, and I'm nor sure why - campbell */
/* TODO: see 2.7x for non-working code */
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
float x, y;
const float snap_point[2] = {
t->tsnap.snapPoint[0] / t->aspect[0],
t->tsnap.snapPoint[1] / t->aspect[1],
};
UI_view2d_view_to_region_fl(&t->region->v2d, UNPACK2(snap_point), &x, &y);
float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE) * U.pixelsize;
GPU_matrix_push_projection();
wmOrtho2_region_pixelspace(t->region);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3ub(255, 255, 255);
imm_draw_circle_wire_2d(pos, x, y, radius, 8);
immUnbindProgram();
GPU_matrix_pop_projection();
}
}
else if (t->spacetype == SPACE_NODE) {
@ -990,17 +1010,19 @@ static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec))
{
BLI_assert(t->spacetype == SPACE_IMAGE);
if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) {
float co[2];
UI_view2d_region_to_view(&t->region->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
t->view_layer, NULL, &objects_len);
float dist_sq = FLT_MAX;
if (ED_uvedit_nearest_uv_multi(
t->scene, objects, objects_len, co, &dist_sq, t->tsnap.snapPoint)) {
float dist_sq = square_f((float)SNAP_MIN_DISTANCE);
if (ED_uvedit_nearest_uv_multi(&t->region->v2d,
t->scene,
objects,
objects_len,
t->mval,
true,
&dist_sq,
t->tsnap.snapPoint)) {
t->tsnap.snapPoint[0] *= t->aspect[0];
t->tsnap.snapPoint[1] *= t->aspect[1];

View File

@ -1019,8 +1019,13 @@ bool uv_find_nearest_vert_multi(Scene *scene,
return found;
}
bool ED_uvedit_nearest_uv(
const Scene *scene, Object *obedit, const float co[2], float *dist_sq, float r_uv[2])
static bool uvedit_nearest_uv(const Scene *scene,
Object *obedit,
const float co[2],
const float scale[2],
const bool ignore_selected,
float *dist_sq,
float r_uv[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMIter iter;
@ -1035,8 +1040,14 @@ bool ED_uvedit_nearest_uv(
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
do {
if (ignore_selected && uvedit_uv_select_test(scene, l_iter, cd_loop_uv_offset)) {
continue;
}
const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
const float dist_test = len_squared_v2v2(co, uv);
float co_tmp[2];
mul_v2_v2v2(co_tmp, scale, uv);
const float dist_test = len_squared_v2v2(co, co_tmp);
if (dist_best > dist_test) {
dist_best = dist_test;
uv_best = uv;
@ -1052,17 +1063,27 @@ bool ED_uvedit_nearest_uv(
return false;
}
bool ED_uvedit_nearest_uv_multi(const Scene *scene,
bool ED_uvedit_nearest_uv_multi(const View2D *v2d,
const Scene *scene,
Object **objects,
const uint objects_len,
const float co[2],
const int mval[2],
const bool ignore_selected,
float *dist_sq,
float r_uv[2])
{
bool found = false;
float scale[2], offset[2];
UI_view2d_scale_get(v2d, &scale[0], &scale[1]);
UI_view2d_view_to_region_fl(v2d, 0.0f, 0.0f, &offset[0], &offset[1]);
float co[2];
sub_v2_v2v2(co, (float[2]){UNPACK2(mval)}, offset);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
if (ED_uvedit_nearest_uv(scene, obedit, co, dist_sq, r_uv)) {
if (uvedit_nearest_uv(scene, obedit, co, scale, ignore_selected, dist_sq, r_uv)) {
found = true;
}
}