Animation: Match Slope slider
It blends selected keys to the slope of neighboring ones. It is used to push the segment closer to the values of the next or previous pose. Co-authored-by: Ares Deveaux <aresdevo@gmail.com> Pull Request: https://projects.blender.org/blender/blender/pulls/110567
This commit is contained in:
committed by
Christoph Lendenfeld
parent
0e2875ede9
commit
bb8766ef01
@@ -774,6 +774,58 @@ void blend_to_ease_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const flo
|
||||
|
||||
/* ---------------- */
|
||||
|
||||
bool match_slope_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
|
||||
{
|
||||
const BezTriple *left_key = fcurve_segment_start_get(fcu, segment->start_index);
|
||||
const BezTriple *right_key = fcurve_segment_end_get(fcu, segment->start_index + segment->length);
|
||||
|
||||
BezTriple beyond_key;
|
||||
const BezTriple *reference_key;
|
||||
|
||||
if (factor >= 0) {
|
||||
/* Stop the function if there is no key beyond the the right neighboring one. */
|
||||
if (segment->start_index + segment->length >= fcu->totvert - 1) {
|
||||
return false;
|
||||
}
|
||||
reference_key = right_key;
|
||||
beyond_key = fcu->bezt[segment->start_index + segment->length + 1];
|
||||
}
|
||||
else {
|
||||
/* Stop the function if there is no key beyond the left neighboring one. */
|
||||
if (segment->start_index <= 1) {
|
||||
return false;
|
||||
}
|
||||
reference_key = left_key;
|
||||
beyond_key = fcu->bezt[segment->start_index - 2];
|
||||
}
|
||||
|
||||
/* This delta values are used to get the relationship between the bookend keys and the
|
||||
* reference keys beyong those. */
|
||||
const float y_delta = beyond_key.vec[1][1] - reference_key->vec[1][1];
|
||||
const float x_delta = beyond_key.vec[1][0] - reference_key->vec[1][0];
|
||||
|
||||
/* Avoids dividing by 0. */
|
||||
if (x_delta == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = segment->start_index; i < segment->start_index + segment->length; i++) {
|
||||
|
||||
/* These new deltas are used to determine the relationship between the current key and the
|
||||
* bookend ones. */
|
||||
const float new_x_delta = fcu->bezt[i].vec[1][0] - reference_key->vec[1][0];
|
||||
const float new_y_delta = new_x_delta * y_delta / x_delta;
|
||||
|
||||
const float delta = reference_key->vec[1][1] + new_y_delta - fcu->bezt[i].vec[1][1];
|
||||
|
||||
const float key_y_value = fcu->bezt[i].vec[1][1] + delta * fabs(factor);
|
||||
BKE_fcurve_keyframe_move_value_with_handles(&fcu->bezt[i], key_y_value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ---------------- */
|
||||
|
||||
void breakdown_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor)
|
||||
{
|
||||
const BezTriple *left_bezt = fcurve_segment_start_get(fcu, segment->start_index);
|
||||
|
||||
@@ -468,6 +468,7 @@ void ease_fcurve_segment(FCurve *fcu, FCurveSegment *segment, float factor);
|
||||
void blend_offset_fcurve_segment(FCurve *fcu, FCurveSegment *segment, float factor);
|
||||
void blend_to_ease_fcurve_segment(FCurve *fcu, FCurveSegment *segment, float factor);
|
||||
bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max);
|
||||
bool match_slope_fcurve_segment(FCurve *fcu, FCurveSegment *segment, float factor);
|
||||
|
||||
/**
|
||||
* Blends the selected keyframes to the default value of the property the F-curve drives.
|
||||
|
||||
@@ -121,6 +121,7 @@ void GRAPH_OT_breakdown(struct wmOperatorType *ot);
|
||||
void GRAPH_OT_ease(struct wmOperatorType *ot);
|
||||
void GRAPH_OT_blend_offset(struct wmOperatorType *ot);
|
||||
void GRAPH_OT_blend_to_ease(struct wmOperatorType *ot);
|
||||
void GRAPH_OT_match_slope(struct wmOperatorType *ot);
|
||||
void GRAPH_OT_decimate(struct wmOperatorType *ot);
|
||||
void GRAPH_OT_blend_to_default(struct wmOperatorType *ot);
|
||||
void GRAPH_OT_butterworth_smooth(struct wmOperatorType *ot);
|
||||
|
||||
@@ -471,6 +471,7 @@ void graphedit_operatortypes()
|
||||
WM_operatortype_append(GRAPH_OT_ease);
|
||||
WM_operatortype_append(GRAPH_OT_blend_offset);
|
||||
WM_operatortype_append(GRAPH_OT_blend_to_ease);
|
||||
WM_operatortype_append(GRAPH_OT_match_slope);
|
||||
WM_operatortype_append(GRAPH_OT_blend_to_default);
|
||||
WM_operatortype_append(GRAPH_OT_gaussian_smooth);
|
||||
WM_operatortype_append(GRAPH_OT_butterworth_smooth);
|
||||
|
||||
@@ -1166,6 +1166,126 @@ void GRAPH_OT_blend_to_ease(wmOperatorType *ot)
|
||||
1.0f);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Match Slope
|
||||
* \{ */
|
||||
|
||||
static void match_slope_graph_keys(bAnimContext *ac, const float factor)
|
||||
{
|
||||
ListBase anim_data = {NULL, NULL};
|
||||
|
||||
bool all_segments_valid = true;
|
||||
|
||||
ANIM_animdata_filter(
|
||||
ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, eAnimCont_Types(ac->datatype));
|
||||
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
|
||||
FCurve *fcu = (FCurve *)ale->key_data;
|
||||
ListBase segments = find_fcurve_segments(fcu);
|
||||
|
||||
LISTBASE_FOREACH (FCurveSegment *, segment, &segments) {
|
||||
all_segments_valid = match_slope_fcurve_segment(fcu, segment, factor);
|
||||
}
|
||||
|
||||
ale->update |= ANIM_UPDATE_DEFAULT;
|
||||
BLI_freelistN(&segments);
|
||||
}
|
||||
|
||||
if(!all_segments_valid) {
|
||||
if (factor >= 0){
|
||||
WM_report(RPT_WARNING, "You need at least 2 keys to the right side of the selection.");
|
||||
}
|
||||
else {
|
||||
WM_report(RPT_WARNING, "You need at least 2 keys to the left side of the selection.");
|
||||
}
|
||||
}
|
||||
|
||||
ANIM_animdata_update(ac, &anim_data);
|
||||
ANIM_animdata_freelist(&anim_data);
|
||||
}
|
||||
|
||||
static void match_slope_draw_status_header(bContext *C, tGraphSliderOp *gso)
|
||||
{
|
||||
common_draw_status_header(C, gso, "Match Slope");
|
||||
}
|
||||
|
||||
static void match_slope_modal_update(bContext *C, wmOperator *op)
|
||||
{
|
||||
tGraphSliderOp *gso = static_cast<tGraphSliderOp *>(op->customdata);
|
||||
|
||||
match_slope_draw_status_header(C, gso);
|
||||
|
||||
/* Reset keyframes to the state at invoke. */
|
||||
reset_bezts(gso);
|
||||
const float factor = slider_factor_get_and_remember(op);
|
||||
match_slope_graph_keys(&gso->ac, factor);
|
||||
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
|
||||
}
|
||||
|
||||
static int match_slope_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
const int invoke_result = graph_slider_invoke(C, op, event);
|
||||
|
||||
if (invoke_result == OPERATOR_CANCELLED) {
|
||||
return invoke_result;
|
||||
}
|
||||
|
||||
tGraphSliderOp *gso = static_cast<tGraphSliderOp *>(op->customdata);
|
||||
gso->modal_update = match_slope_modal_update;
|
||||
gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
|
||||
match_slope_draw_status_header(C, gso);
|
||||
ED_slider_allow_overshoot_set(gso->slider, false, false);
|
||||
ED_slider_factor_bounds_set(gso->slider, -1, 1);
|
||||
ED_slider_factor_set(gso->slider, 0.0f);
|
||||
|
||||
return invoke_result;
|
||||
}
|
||||
|
||||
static int match_slope_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
bAnimContext ac;
|
||||
|
||||
/* Get editor data. */
|
||||
if (ANIM_animdata_get_context(C, &ac) == 0) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
const float factor = RNA_float_get(op->ptr, "factor");
|
||||
|
||||
match_slope_graph_keys(&ac, factor);
|
||||
|
||||
/* Set notifier that keyframes have changed. */
|
||||
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void GRAPH_OT_match_slope(wmOperatorType *ot)
|
||||
{
|
||||
/* Identifiers. */
|
||||
ot->name = "Match Slope";
|
||||
ot->idname = "GRAPH_OT_match_slope";
|
||||
ot->description = "Blend selected keys to the slope of neighboring ones";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->invoke = match_slope_invoke;
|
||||
ot->modal = graph_slider_modal;
|
||||
ot->exec = match_slope_exec;
|
||||
ot->poll = graphop_editable_keyframes_poll;
|
||||
|
||||
/* Flags. */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
RNA_def_float_factor(ot->srna,
|
||||
"factor",
|
||||
0.0f,
|
||||
-FLT_MAX,
|
||||
FLT_MAX,
|
||||
"Factor",
|
||||
"Defines which keys to use as slope and how much to blend towards them",
|
||||
-1.0f,
|
||||
1.0f);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Gauss Smooth Operator
|
||||
|
||||
Reference in New Issue
Block a user