ANIM: optimize proportional editing many keys in the Graph Editor

Part one.

We have to determine distances for proportional editing for all three
`TransData` (representing the key as well as both handles). The way
#bezt_to_transdata sets up the `TransData`, the `td->center[0]` will
always be based on the **key** (bezt->vec[1]) which means that
#graph_key_shortest_dist will return the same for all of them and we can
reuse that (expensive) result if needed.

Depending on the situation, we can save two thirds of the time spent
here... (42sec >> 14sec before we can actually start transforming keys
in the file from #139042)

Might be worth looking into using a 2D KDTree in the future as well.

(also corrects a code comment about what is actually done in a
particular code path)

Noticed while looking into #139042

Pull Request: https://projects.blender.org/blender/blender/pulls/139164
This commit is contained in:
Philipp Oeser
2025-05-28 08:33:57 +02:00
committed by Philipp Oeser
parent 795f589989
commit 1345ed9214

View File

@@ -210,26 +210,28 @@ static void graph_bezt_get_transform_selection(const TransInfo *t,
*r_right_handle = right;
}
static void graph_key_shortest_dist(
static float graph_key_shortest_dist(
TransInfo *t, FCurve *fcu, TransData *td_start, TransData *td, int cfra, bool use_handle)
{
int j = 0;
TransData *td_iter = td_start;
bool sel_key, sel_left, sel_right;
td->dist = FLT_MAX;
float dist = FLT_MAX;
for (; j < fcu->totvert; j++) {
BezTriple *bezt = fcu->bezt + j;
if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
graph_bezt_get_transform_selection(t, bezt, use_handle, &sel_left, &sel_key, &sel_right);
if (sel_left || sel_key || sel_right) {
td->dist = td->rdist = min_ff(td->dist, fabs(td_iter->center[0] - td->center[0]));
dist = min_ff(td->dist, fabs(td_iter->center[0] - td->center[0]));
}
td_iter += 3;
}
}
return dist;
}
/**
@@ -580,7 +582,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
}
if (is_prop_edit) {
/* Loop 2: build transdata arrays. */
/* Loop 3: build proportional edit distances. */
td = tc->data;
for (bAnimListElem *ale : unique_fcu_anim_list_elements) {
@@ -603,29 +605,28 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
graph_bezt_get_transform_selection(t, bezt, use_handle, &sel_left, &sel_key, &sel_right);
if (sel_left || sel_key) {
td->dist = td->rdist = 0.0f;
}
else {
graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
}
td++;
/* Now determine to distance for proportional editing for all three TransData
* (representing the key as well as both handles). Note though that the way
* #bezt_to_transdata sets up the TransData, the td->center[0] will always be based on
* the key (bezt->vec[1]) which means that #graph_key_shortest_dist will return the
* same for all of them and we can reuse that (expensive) result if needed. Might be
* worth looking into using a 2D KDTree in the future as well. */
if (sel_key) {
td->dist = td->rdist = 0.0f;
float dist = FLT_MAX;
if (sel_left || sel_key || sel_right) {
/* If either left handle or key or right handle is selected, all will move fully. */
dist = 0.0f;
}
else {
graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
/* If nothing is selected, left handle and key and right handle will share the same (to
* be calculated) distance. */
dist = graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
}
td++;
if (sel_right || sel_key) {
td->dist = td->rdist = 0.0f;
}
else {
graph_key_shortest_dist(t, fcu, td_start, td, cfra, use_handle);
}
td++;
td->dist = td->rdist = dist;
(td + 1)->dist = (td + 1)->rdist = dist;
(td + 2)->dist = (td + 2)->rdist = dist;
td += 3;
}
}
}