From a452fcb9a5495ecbbbaedb7e5c631814c7f4372a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 7 Nov 2020 20:16:32 +1100 Subject: View3D: take clipping into account for Frame All Clamp the min/max used for Frame All/Selected by the clipping region if it's set. Resolve T81050 --- source/blender/editors/include/ED_view3d.h | 2 + source/blender/editors/space_view3d/view3d_edit.c | 10 ++++ source/blender/editors/space_view3d/view3d_utils.c | 70 ++++++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index f64c6a42f18..a0246174970 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -459,6 +459,8 @@ void ED_view3d_clipping_calc(struct BoundBox *bb, const struct ARegion *region, const struct Object *ob, const struct rcti *rect); +bool ED_view3d_clipping_clamp_minmax(const struct RegionView3D *rv3d, float min[3], float max[3]); + void ED_view3d_clipping_local(struct RegionView3D *rv3d, const float mat[4][4]); bool ED_view3d_clipping_test(const struct RegionView3D *rv3d, const float co[3], diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 897777c9159..c16cd94d90d 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -2978,6 +2978,11 @@ static int view3d_all_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } + if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { + /* This is an approximation, see function documentation for details. */ + ED_view3d_clipping_clamp_minmax(rv3d, min, max); + } + if (use_all_regions) { view3d_from_minmax_multi(C, v3d, min, max, true, smooth_viewtx); } @@ -3125,6 +3130,11 @@ static int viewselected_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } + if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { + /* This is an approximation, see function documentation for details. */ + ED_view3d_clipping_clamp_minmax(rv3d, min, max); + } + if (use_all_regions) { view3d_from_minmax_multi(C, v3d, min, max, ok_dist, smooth_viewtx); } diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 22cdbb090a5..c334b2ce541 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -330,6 +330,76 @@ void ED_view3d_clipping_calc( /** \} */ +/* -------------------------------------------------------------------- */ +/** \name View Clipping Clamp Min/Max + * \{ */ + +struct PointsInPlanesMinMax_UserData { + float min[3]; + float max[3]; +}; + +static void points_in_planes_minmax_fn( + const float co[3], int UNUSED(i), int UNUSED(j), int UNUSED(k), void *user_data_p) +{ + struct PointsInPlanesMinMax_UserData *user_data = user_data_p; + minmax_v3v3_v3(user_data->min, user_data->max, co); +} + +/** + * Clamp min/max by the viewport clipping. + * + * \note This is an approximation, with the limitation that the bounding box from the (mix, max) + * calculation might not have any geometry inside the clipped region. + * Performing a clipping test on each vertex would work well enough for most cases, + * although it's not perfect either as edges/faces may intersect the clipping without having any + * of their vertices inside it. + * A more accurate result would be quite involved. + * + * \return True when the arguments were clamped. + */ +bool ED_view3d_clipping_clamp_minmax(const RegionView3D *rv3d, float min[3], float max[3]) +{ + /* 6 planes for the cube, 4..6 for the current view clipping planes. */ + float planes[6 + 6][4]; + + /* Convert the min/max to 6 planes. */ + for (int i = 0; i < 3; i++) { + float *plane_min = planes[(i * 2) + 0]; + float *plane_max = planes[(i * 2) + 1]; + zero_v3(plane_min); + zero_v3(plane_max); + plane_min[i] = -1.0f; + plane_min[3] = +min[i]; + plane_max[i] = +1.0f; + plane_max[3] = -max[i]; + } + + /* Copy planes from the viewport & flip. */ + int planes_len = 6; + int clip_len = (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXCLIP) ? 4 : 6; + for (int i = 0; i < clip_len; i++) { + negate_v4_v4(planes[planes_len], rv3d->clip[i]); + planes_len += 1; + } + + /* Calculate points intersecting all planes (effectively intersecting two bounding boxes). */ + struct PointsInPlanesMinMax_UserData user_data; + INIT_MINMAX(user_data.min, user_data.max); + + const float eps_coplanar = 1e-4f; + const float eps_isect = 1e-6f; + if (isect_planes_v3_fn( + planes, planes_len, eps_coplanar, eps_isect, points_in_planes_minmax_fn, &user_data)) { + copy_v3_v3(min, user_data.min); + copy_v3_v3(max, user_data.max); + return true; + } + return false; +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name View Bound-Box Utilities * -- cgit v1.2.3