From 011327224ecec1312e0780865a1fb0dc83830a30 Mon Sep 17 00:00:00 2001 From: jon denning Date: Wed, 29 Jun 2022 20:52:00 -0400 Subject: Transform Snap: nearest face snap mode, snapping options, refactoring. This commit adds a new face nearest snapping mode, adds new snapping options, and (lightly) refactors code around snapping. The new face nearest snapping mode will snap transformed geometry to the nearest surface in world space. In contrast, the original face snapping mode uses projection (raycasting) to snap source to target geometry. Face snapping therefore only works with what is visible, while nearest face snapping can snap geometry to occluded parts of the scene. This new mode is critical for retopology work, where some of the target mesh might be occluded (ex: sliding an edge loop that wraps around the backside of target mesh). The nearest face snapping mode has two options: "Snap to Same Target" and "Face Nearest Steps". When the Snap to Same Object option is enabled, the selected source geometry will stay near the target that it is nearest before editing started, which prevents the source geometry from snapping to other targets. The Face Nearest Steps divides the overall transformation for each vertex into n smaller transformations, then applies those n transformations with surface snapping interlacing each step. This steps option handles transformations that cross U-shaped targets better. The new snapping options allow the artist to better control which target objects (objects to which the edited geometry is snapped) are considered when snapping. In particular, the only option for filtering target objects was a "Project onto Self", which allowed the currently edited mesh to be considered as a target. Now, the artist can choose any combination of the following to be considered as a target: the active object, any edited object that isn't active (see note below), any non- edited object. Additionally, the artist has another snapping option to exclude objects that are not selectable as potential targets. The Snapping Options dropdown has been lightly reorganized to allow for the additional options. Included in this patch: - Snap target selection is more controllable for artist with additional snapping options. - Renamed a few of the snap-related functions to better reflect what they actually do now. For example, `applySnapping` implies that this handles the snapping, while `applyProject` implies something entirely different is done there. However, better names would be `applySnappingAsGroup` and `applySnappingIndividual`, respectively, where `applySnappingIndividual` previously only does Face snapping. - Added an initial coordinate parameter to snapping functions so that the nearest target before transforming can be determined(for "Snap to Same Object"), and so the transformation can be broken into smaller steps (for "Face Nearest Steps"). - Separated the BVH Tree getter code from mesh/edit mesh to its own function to reduce code duplication. - Added icon for nearest face snapping. - The original "Project onto Self" was actually not correct! This option should be called "Project onto Active" instead, but that only matters when editing multiple meshes at the same time. This patch makes this change in the UI. Reviewed By: Campbell Barton, Germano Cavalcante Differential Revision: https://developer.blender.org/D14591 --- source/blender/editors/transform/transform_mode_edge_slide.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender/editors/transform/transform_mode_edge_slide.c') diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c index b8e9a0d1a4d..a3c49d2362f 100644 --- a/source/blender/editors/transform/transform_mode_edge_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_slide.c @@ -1292,7 +1292,7 @@ static void edge_slide_snap_apply(TransInfo *t, float *value) side_index = t_snap >= t_mid; } - if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE)) { + if (t->tsnap.snapElem & (SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST)) { float co_dir[3]; sub_v3_v3v3(co_dir, co_dest[side_index], co_orig); normalize_v3(co_dir); @@ -1444,7 +1444,7 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2])) final = t->values[0] + t->values_modal_offset[0]; - applySnapping(t, &final); + applySnappingAsGroup(t, &final); if (!validSnap(t)) { transform_snap_increment(t, &final); } -- cgit v1.2.3 From c7a7aee004d96d3502d8246d9bf78f34a6dd5a0b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 9 Aug 2022 14:18:18 +1000 Subject: Cleanup: use own username in code-comment tags --- source/blender/editors/transform/transform_mode_edge_slide.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/editors/transform/transform_mode_edge_slide.c') diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c index a3c49d2362f..b48ba0640ad 100644 --- a/source/blender/editors/transform/transform_mode_edge_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_slide.c @@ -1204,7 +1204,7 @@ void drawEdgeSlide(TransInfo *t) immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade); immBegin(GPU_PRIM_LINES, sld->totsv * 2); - /* TODO(campbell): Loop over all verts. */ + /* TODO(@campbellbarton): Loop over all verts. */ sv = sld->sv; for (i = 0; i < sld->totsv; i++, sv++) { float a[3], b[3]; -- cgit v1.2.3 From 3c060b2216b868eec99bb0acb3534c3780344774 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 26 Aug 2022 13:17:30 -0300 Subject: Fix T100633: Node Editor: Edge scrolling breaks node snapping The view offset, calculated by the Edge Pan system, only affects the position of the nodes, but forget to update: - snapping data - final value of transform - values used for custom drawing Therefore, to avoid having to update a lot of scattered data, the `transformViewUpdate` utility has been implemented to recalculate input values when the view changes. This utility does more than is necessary to fix the bug, but with that, it can work in any situation. --- .../editors/transform/transform_mode_edge_slide.c | 156 +++++++++++++-------- 1 file changed, 100 insertions(+), 56 deletions(-) (limited to 'source/blender/editors/transform/transform_mode_edge_slide.c') diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c index b48ba0640ad..85285e38bdd 100644 --- a/source/blender/editors/transform/transform_mode_edge_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_slide.c @@ -292,6 +292,73 @@ static BMLoop *get_next_loop( return NULL; } +static void edge_slide_projmat_get(TransInfo *t, TransDataContainer *tc, float r_projectMat[4][4]) +{ + RegionView3D *rv3d = NULL; + + if (t->spacetype == SPACE_VIEW3D) { + /* Background mode support. */ + rv3d = t->region ? t->region->regiondata : NULL; + } + + if (!rv3d) { + /* Ok, let's try to survive this. */ + unit_m4(r_projectMat); + } + else { + ED_view3d_ob_project_mat_get(rv3d, tc->obedit, r_projectMat); + } +} + +static void edge_slide_pair_project(TransDataEdgeSlideVert *sv, + ARegion *region, + float projectMat[4][4], + float r_sco_a[3], + float r_sco_b[3]) +{ + BMVert *v = sv->v; + + if (sv->v_side[1]) { + ED_view3d_project_float_v3_m4(region, sv->v_side[1]->co, r_sco_b, projectMat); + } + else { + add_v3_v3v3(r_sco_b, v->co, sv->dir_side[1]); + ED_view3d_project_float_v3_m4(region, r_sco_b, r_sco_b, projectMat); + } + + if (sv->v_side[0]) { + ED_view3d_project_float_v3_m4(region, sv->v_side[0]->co, r_sco_a, projectMat); + } + else { + add_v3_v3v3(r_sco_a, v->co, sv->dir_side[0]); + ED_view3d_project_float_v3_m4(region, r_sco_a, r_sco_a, projectMat); + } +} + +static void edge_slide_data_init_mval(MouseInput *mi, EdgeSlideData *sld, float *mval_dir) +{ + /* Possible all of the edge loops are pointing directly at the view. */ + if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) { + mval_dir[0] = 0.0f; + mval_dir[1] = 100.0f; + } + + float mval_start[2], mval_end[2]; + + /* Zero out Start. */ + zero_v2(mval_start); + + /* dir holds a vector along edge loop */ + copy_v2_v2(mval_end, mval_dir); + mul_v2_fl(mval_end, 0.5f); + + sld->mval_start[0] = mi->imval[0] + mval_start[0]; + sld->mval_start[1] = mi->imval[1] + mval_start[1]; + + sld->mval_end[0] = mi->imval[0] + mval_end[0]; + sld->mval_end[1] = mi->imval[1] + mval_end[1]; +} + /** * Calculate screenspace `mval_start` / `mval_end`, optionally slide direction. */ @@ -308,29 +375,20 @@ static void calcEdgeSlide_mval_range(TransInfo *t, BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); ARegion *region = t->region; View3D *v3d = NULL; - RegionView3D *rv3d = NULL; float projectMat[4][4]; BMBVHTree *bmbvh; /* only for use_calc_direction */ float(*loop_dir)[3] = NULL, *loop_maxdist = NULL; - float mval_start[2], mval_end[2]; float mval_dir[3], dist_best_sq; if (t->spacetype == SPACE_VIEW3D) { /* background mode support */ v3d = t->area ? t->area->spacedata.first : NULL; - rv3d = t->region ? t->region->regiondata : NULL; } - if (!rv3d) { - /* ok, let's try to survive this */ - unit_m4(projectMat); - } - else { - ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat); - } + edge_slide_projmat_get(t, tc, projectMat); if (use_occlude_geometry) { bmbvh = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false); @@ -379,21 +437,7 @@ static void calcEdgeSlide_mval_range(TransInfo *t, continue; } - if (sv->v_side[1]) { - ED_view3d_project_float_v3_m4(region, sv->v_side[1]->co, sco_b, projectMat); - } - else { - add_v3_v3v3(sco_b, v->co, sv->dir_side[1]); - ED_view3d_project_float_v3_m4(region, sco_b, sco_b, projectMat); - } - - if (sv->v_side[0]) { - ED_view3d_project_float_v3_m4(region, sv->v_side[0]->co, sco_a, projectMat); - } - else { - add_v3_v3v3(sco_a, v->co, sv->dir_side[0]); - ED_view3d_project_float_v3_m4(region, sco_a, sco_a, projectMat); - } + edge_slide_pair_project(sv, region, projectMat, sco_a, sco_b); /* global direction */ dist_sq = dist_squared_to_line_segment_v2(mval, sco_b, sco_a); @@ -433,24 +477,7 @@ static void calcEdgeSlide_mval_range(TransInfo *t, MEM_freeN(loop_maxdist); } - /* possible all of the edge loops are pointing directly at the view */ - if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) { - mval_dir[0] = 0.0f; - mval_dir[1] = 100.0f; - } - - /* zero out start */ - zero_v2(mval_start); - - /* dir holds a vector along edge loop */ - copy_v2_v2(mval_end, mval_dir); - mul_v2_fl(mval_end, 0.5f); - - sld->mval_start[0] = t->mval[0] + mval_start[0]; - sld->mval_start[1] = t->mval[1] + mval_start[1]; - - sld->mval_end[0] = t->mval[0] + mval_end[0]; - sld->mval_end[1] = t->mval[1] + mval_end[1]; + edge_slide_data_init_mval(&t->mouse, sld, mval_dir); if (bmbvh) { BKE_bmbvh_free(bmbvh); @@ -466,7 +493,6 @@ static void calcEdgeSlide_even(TransInfo *t, if (sld->totsv > 0) { ARegion *region = t->region; - RegionView3D *rv3d = NULL; float projectMat[4][4]; int i = 0; @@ -475,18 +501,7 @@ static void calcEdgeSlide_even(TransInfo *t, float dist_sq = 0; float dist_min_sq = FLT_MAX; - if (t->spacetype == SPACE_VIEW3D) { - /* background mode support */ - rv3d = t->region ? t->region->regiondata : NULL; - } - - if (!rv3d) { - /* ok, let's try to survive this */ - unit_m4(projectMat); - } - else { - ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat); - } + edge_slide_projmat_get(t, tc, projectMat); for (i = 0; i < sld->totsv; i++, sv++) { /* Set length */ @@ -1553,3 +1568,32 @@ void initEdgeSlide(TransInfo *t) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mouse Input Utilities + * \{ */ + +void transform_mode_edge_slide_reproject_input(TransInfo *t) +{ + ARegion *region = t->region; + + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + EdgeSlideData *sld = tc->custom.mode.data; + if (sld) { + float projectMat[4][4]; + edge_slide_projmat_get(t, tc, projectMat); + + TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index]; + + float mval_dir[3], sco_a[3], sco_b[3]; + edge_slide_pair_project(curr_sv, region, projectMat, sco_a, sco_b); + sub_v3_v3v3(mval_dir, sco_b, sco_a); + edge_slide_data_init_mval(&t->mouse, sld, mval_dir); + } + } + + EdgeSlideData *sld = edgeSlideFirstGet(t); + setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start); +} + +/** \} */ -- cgit v1.2.3