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
This commit is contained in:
parent
fb1265c5cf
commit
9baf39c8da
Notes:
blender-bot
2023-02-14 05:12:59 +01:00
Referenced by issue #86666, Using Lasso and Circle select tools, objects which are not visible due to camera clipping are also selected.
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue