From 9baf39c8daded5b000d4eacc6c677dbfd3359478 Mon Sep 17 00:00:00 2001 From: Germano Cavalcante Date: Fri, 19 Mar 2021 15:10:51 -0300 Subject: Fix T86666: Lasso and Circle select tools selecting objects behind clip_min Although it works well in most cases, the algorithm to detect if a point is within the limits of the camera does not work well in othographic mode. This commit also adds the option `V3D_PROJ_TEST_CLIP_FAR` (currently unused). Differential Revision: https://developer.blender.org/D10771 --- source/blender/editors/include/ED_view3d.h | 16 ++++--- .../blender/editors/space_view3d/view3d_project.c | 51 ++++++++++------------ .../blender/editors/space_view3d/view3d_select.c | 16 +++---- 3 files changed, 37 insertions(+), 46 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index a63b133cc22..3b8e062ffec 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -163,14 +163,16 @@ typedef enum { V3D_PROJ_RET_OK = 0, /** can't avoid this when in perspective mode, (can't avoid) */ V3D_PROJ_RET_CLIP_NEAR = 1, + /** After clip_end. */ + V3D_PROJ_RET_CLIP_FAR = 2, /** so close to zero we can't apply a perspective matrix usefully */ - V3D_PROJ_RET_CLIP_ZERO = 2, + V3D_PROJ_RET_CLIP_ZERO = 3, /** bounding box clip - RV3D_CLIPPING */ - V3D_PROJ_RET_CLIP_BB = 3, + V3D_PROJ_RET_CLIP_BB = 4, /** outside window bounds */ - V3D_PROJ_RET_CLIP_WIN = 4, + V3D_PROJ_RET_CLIP_WIN = 5, /** outside range (mainly for short), (can't avoid) */ - V3D_PROJ_RET_OVERFLOW = 5, + V3D_PROJ_RET_OVERFLOW = 6, } eV3DProjStatus; /* some clipping tests are optional */ @@ -179,14 +181,14 @@ typedef enum { V3D_PROJ_TEST_CLIP_BB = (1 << 0), V3D_PROJ_TEST_CLIP_WIN = (1 << 1), V3D_PROJ_TEST_CLIP_NEAR = (1 << 2), - V3D_PROJ_TEST_CLIP_ZERO = (1 << 3), + V3D_PROJ_TEST_CLIP_FAR = (1 << 3), + V3D_PROJ_TEST_CLIP_ZERO = (1 << 4), } eV3DProjTest; #define V3D_PROJ_TEST_CLIP_DEFAULT \ (V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) #define V3D_PROJ_TEST_ALL \ - (V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR | \ - V3D_PROJ_TEST_CLIP_ZERO) + (V3D_PROJ_TEST_CLIP_DEFAULT | V3D_PROJ_TEST_CLIP_FAR | V3D_PROJ_TEST_CLIP_ZERO) /* view3d_iterators.c */ diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index 58538fc3ecb..24d34e514c5 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -38,7 +38,6 @@ #include "ED_view3d.h" /* own include */ -#define BL_NEAR_CLIP 0.001 #define BL_ZERO_CLIP 0.001 /* Non Clipping Projection Functions @@ -139,38 +138,32 @@ static eV3DProjStatus ed_view3d_project__internal(const ARegion *region, copy_v3_v3(vec4, co); vec4[3] = 1.0; mul_m4_v4(perspmat, vec4); + const float w = fabsf(vec4[3]); - if (((flag & V3D_PROJ_TEST_CLIP_ZERO) == 0) || (fabsf(vec4[3]) > (float)BL_ZERO_CLIP)) { - if (((flag & V3D_PROJ_TEST_CLIP_NEAR) == 0) || (vec4[3] > (float)BL_NEAR_CLIP)) { - const float scalar = (vec4[3] != 0.0f) ? (1.0f / vec4[3]) : 0.0f; - const float fx = ((float)region->winx / 2.0f) * (1.0f + (vec4[0] * scalar)); - if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fx > 0.0f && fx < (float)region->winx)) { - const float fy = ((float)region->winy / 2.0f) * (1.0f + (vec4[1] * scalar)); - if (((flag & V3D_PROJ_TEST_CLIP_WIN) == 0) || (fy > 0.0f && fy < (float)region->winy)) { - r_co[0] = fx; - r_co[1] = fy; - - /* check if the point is behind the view, we need to flip in this case */ - if (UNLIKELY((flag & V3D_PROJ_TEST_CLIP_NEAR) == 0) && (vec4[3] < 0.0f)) { - negate_v2(r_co); - } - } - else { - return V3D_PROJ_RET_CLIP_WIN; - } - } - else { - return V3D_PROJ_RET_CLIP_WIN; - } - } - else { - return V3D_PROJ_RET_CLIP_NEAR; - } - } - else { + if ((flag & V3D_PROJ_TEST_CLIP_ZERO) && (w <= (float)BL_ZERO_CLIP)) { return V3D_PROJ_RET_CLIP_ZERO; } + if ((flag & V3D_PROJ_TEST_CLIP_NEAR) && (vec4[2] <= -w)) { + return V3D_PROJ_RET_CLIP_NEAR; + } + + if ((flag & V3D_PROJ_TEST_CLIP_FAR) && (vec4[2] >= w)) { + return V3D_PROJ_RET_CLIP_FAR; + } + + const float scalar = (w != 0.0f) ? (1.0f / w) : 0.0f; + const float fx = ((float)region->winx / 2.0f) * (1.0f + (vec4[0] * scalar)); + const float fy = ((float)region->winy / 2.0f) * (1.0f + (vec4[1] * scalar)); + + if ((flag & V3D_PROJ_TEST_CLIP_WIN) && + (fx <= 0.0f || fy <= 0.0f || fx >= (float)region->winx || fy >= (float)region->winy)) { + return V3D_PROJ_RET_CLIP_WIN; + } + + r_co[0] = fx; + r_co[1] = fy; + return V3D_PROJ_RET_OK; } diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 7dc4a72e510..3166b818d3c 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -2054,11 +2054,9 @@ static bool ed_object_select_pick(bContext *C, while (base) { if (BASE_SELECTABLE(v3d, base)) { float screen_co[2]; - if (ED_view3d_project_float_global(region, - base->object->obmat[3], - screen_co, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | - V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { + if (ED_view3d_project_float_global( + region, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) == + V3D_PROJ_RET_OK) { float dist_temp = len_manhattan_v2v2(mval_fl, screen_co); if (base == oldbasact) { dist_temp += 10.0f; @@ -4054,11 +4052,9 @@ static bool object_circle_select(ViewContext *vc, for (base = FIRSTBASE(view_layer); base; base = base->next) { if (BASE_SELECTABLE(v3d, base) && ((base->flag & BASE_SELECTED) != select_flag)) { float screen_co[2]; - if (ED_view3d_project_float_global(vc->region, - base->object->obmat[3], - screen_co, - V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | - V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { + if (ED_view3d_project_float_global( + vc->region, base->object->obmat[3], screen_co, V3D_PROJ_TEST_CLIP_DEFAULT) == + V3D_PROJ_RET_OK) { if (len_squared_v2v2(mval_fl, screen_co) <= radius_squared) { ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); changed = true; -- cgit v1.2.3