Fix #125646: Resolve edge-slide performance regression #128016

Manually merged
Campbell Barton merged 6 commits from ideasman42/blender:pr-125646-fix into main 2024-09-24 07:42:57 +02:00

View File

@ -9,13 +9,15 @@
#include "BLI_math_matrix.h"
#include "BLI_string.h"
#include "BKE_editmesh.hh"
#include "BKE_editmesh_bvh.h"
#include "BKE_unit.hh"
#include "GPU_immediate.hh"
#include "GPU_matrix.hh"
#include "ED_mesh.hh"
#include "ED_screen.hh"
#include "ED_transform_snap_object_context.hh"
#include "WM_api.hh"
@ -180,59 +182,22 @@ static void edge_slide_data_init_mval(MouseInput *mi, EdgeSlideData *sld, float
sld->mval_end[1] = mi->imval[1] + mval_end[1];
}
static bool is_vert_slide_visible(TransInfo *t,
SnapObjectContext *sctx,
TransDataEdgeSlideVert *sv,
const float4x4 &obmat,
const float4 &plane_near)
static bool is_vert_slide_visible_bmesh(TransInfo *t,
TransDataContainer *tc,
View3D *v3d,
BMBVHTree *bmbvh,
TransDataEdgeSlideVert *sv)
{
const float3 &v_co_orig = sv->v_co_orig();
float3 points[3] = {
v_co_orig,
v_co_orig + sv->dir_side[0] * 0.9f,
v_co_orig + sv->dir_side[1] * 0.9f,
};
BMIter iter_other;
BMEdge *e;
float3 hit_loc;
for (float3 &p : points) {
p = math::transform_point(obmat, p);
float3 view_vec;
float lambda, ray_depth = FLT_MAX;
transform_view_vector_calc(t, p, view_vec);
if (dot_v3v3(view_vec, plane_near) > 0.0f) {
/* Behind the view origin. */
return false;
BMVert *v = static_cast<BMVert *>(sv->td->extra);
BM_ITER_ELEM (e, &iter_other, v, BM_EDGES_OF_VERT) {
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
continue;
}
if (!isect_ray_plane_v3(p, view_vec, plane_near, &lambda, false)) {
return false;
}
float3 view_orig = p + view_vec * lambda;
SnapObjectParams snap_object_params{};
snap_object_params.snap_target_select = t->tsnap.target_operation;
snap_object_params.edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL;
snap_object_params.use_occlusion_test = false;
snap_object_params.use_backface_culling = (t->tsnap.flag & SCE_SNAP_BACKFACE_CULLING) != 0;
bool has_hit = ED_transform_snap_object_project_ray_ex(sctx,
t->depsgraph,
static_cast<const View3D *>(t->view),
&snap_object_params,
view_orig,
-view_vec,
&ray_depth,
hit_loc,
nullptr,
nullptr,
nullptr,
nullptr);
const bool is_occluded = has_hit && lambda > (ray_depth + 0.0001f);
if (!is_occluded) {
if (BMBVH_EdgeVisible(bmbvh, e, t->depsgraph, t->region, v3d, tc->obedit)) {
return true;
}
}
@ -243,27 +208,29 @@ static bool is_vert_slide_visible(TransInfo *t,
* Calculate screen-space `mval_start` / `mval_end`, optionally slide direction.
*/
static void calcEdgeSlide_mval_range(TransInfo *t,
TransDataContainer *tc,
EdgeSlideData *sld,
const int loop_nr,
const float2 &mval,
const bool use_calc_direction)
{
View3D *v3d = nullptr;
/* Use for visibility checks. */
SnapObjectContext *snap_context = nullptr;
bool use_occlude_geometry = false;
const float4x4 *obmat = nullptr;
float4 plane_near;
if (t->spacetype == SPACE_VIEW3D) {
View3D *v3d = static_cast<View3D *>(t->area ? t->area->spacedata.first : nullptr);
Object *obedit = TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit;
use_occlude_geometry = (v3d && obedit->dt > OB_WIRE && !XRAY_ENABLED(v3d));
if (use_occlude_geometry) {
obmat = &obedit->object_to_world();
planes_from_projmat(t->persmat, nullptr, nullptr, nullptr, nullptr, plane_near, nullptr);
snap_context = ED_transform_snap_object_context_create(t->scene, 0);
v3d = static_cast<View3D *>(t->area ? t->area->spacedata.first : nullptr);
if (tc->obedit->type == OB_MESH) {
use_occlude_geometry = (v3d && tc->obedit->dt > OB_WIRE && !XRAY_ENABLED(v3d));
}
}
BMBVHTree *bmbvh = nullptr;
if (use_occlude_geometry) {
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
bmbvh = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, nullptr, false);
}
ideasman42 marked this conversation as resolved Outdated

Does this work if we use Edge Slide on a UV?

Does this work if we use Edge Slide on a UV?

I've since split the BMesh part out, so UV's are handled in a separate loop.

I've since split the BMesh part out, so UV's are handled in a separate loop.
/* Find mouse vectors, the global one, and one per loop in case we have
* multiple loops selected, in case they are oriented different. */
float2 mval_dir = float2(0);
@ -281,8 +248,7 @@ static void calcEdgeSlide_mval_range(TransInfo *t,
for (int i : sld->sv.index_range()) {
TransDataEdgeSlideVert *sv = &sld->sv[i];
bool is_visible = !use_occlude_geometry ||
is_vert_slide_visible(t, snap_context, sv, *obmat, plane_near);
bool is_visible = !use_occlude_geometry || is_vert_slide_visible_bmesh(t, tc, v3d, bmbvh, sv);
ideasman42 marked this conversation as resolved Outdated

We are re-projecting and re-testing the same sliding coordinates for each linked edge.

The is_visible logic should be moved to a function in order to break the loop at the first visible edge and only test once.

We are re-projecting and re-testing the same sliding coordinates for each linked edge. The `is_visible` logic should be moved to a function in order to break the loop at the first visible edge and only test once.
/* This test is only relevant if object is not wire-drawn! See #32068. */
if (!is_visible && !use_calc_direction) {
@ -330,8 +296,8 @@ static void calcEdgeSlide_mval_range(TransInfo *t,
edge_slide_data_init_mval(&t->mouse, sld, mval_dir);
if (snap_context) {
ED_transform_snap_object_context_destroy(snap_context);
if (bmbvh) {
BKE_bmbvh_free(bmbvh);
}
}
@ -385,7 +351,7 @@ static EdgeSlideData *createEdgeSlideVerts(TransInfo *t,
sld->curr_sv_index = 0;
sld->update_proj_mat(t, tc);
calcEdgeSlide_mval_range(t, sld, group_len, t->mval, use_double_side);
calcEdgeSlide_mval_range(t, tc, sld, group_len, t->mval, use_double_side);
return sld;
}