diff options
author | Joshua Leung <aligorith@gmail.com> | 2011-03-12 04:09:40 +0300 |
---|---|---|
committer | Joshua Leung <aligorith@gmail.com> | 2011-03-12 04:09:40 +0300 |
commit | 80de27914d4d0cedf8a46d960b496db7126d118e (patch) | |
tree | bc31cd5536c11ffc213a608848344152470cc877 /source/blender/editors/animation | |
parent | c786a2c80506397f64d3bc3ad91d97774e867d8d (diff) |
Bugfix [#26222] Alt-O (smooth) in Graph editor destroys fcurve handle
type and data
Recoded Keyframe Smoothing operator to work better for continuous
curves (i.e. ones with monotonically increasing slopes in sections) as
opposed to hypothetically jagged ones.
The old method assumed that handles should be flat as otherwise, you'd
often get unsmooth curves just because you went and tilted some of the
handles for local extrema, causing some unkeyframed overshoots, which
also leads to changes in timing, which in turn often means unsmooth
motion. Hence, the code took advantage of this to do things with less
extra data.
However, now we have a proper "flatten handles" tool (under snap ->
horizontal) so this functionality is not needed in the general case
where it will lead to stair-stepping artifacts.
Diffstat (limited to 'source/blender/editors/animation')
-rw-r--r-- | source/blender/editors/animation/keyframes_general.c | 46 |
1 files changed, 22 insertions, 24 deletions
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index 53d8b4d67f1..07069a69c40 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -279,28 +279,21 @@ void clean_fcurve(FCurve *fcu, float thresh) /* temp struct used for smooth_fcurve */ typedef struct tSmooth_Bezt { float *h1, *h2, *h3; /* bezt->vec[0,1,2][1] */ + float y1, y2, y3; /* averaged before/new/after y-values */ } tSmooth_Bezt; /* Use a weighted moving-means method to reduce intensity of fluctuations */ +// TODO: introduce scaling factor for weighting falloff void smooth_fcurve (FCurve *fcu) { BezTriple *bezt; int i, x, totSel = 0; - /* first loop through - count how many verts are selected, and fix up handles - * this is done for both modes - */ + /* first loop through - count how many verts are selected */ bezt= fcu->bezt; for (i=0; i < fcu->totvert; i++, bezt++) { - if (BEZSELECTED(bezt)) { - /* line point's handles up with point's vertical position */ - bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1]; - if ((bezt->h1==HD_AUTO) || (bezt->h1==HD_VECT)) bezt->h1= HD_ALIGN; - if ((bezt->h2==HD_AUTO) || (bezt->h2==HD_VECT)) bezt->h2= HD_ALIGN; - - /* add value to total */ + if (BEZSELECTED(bezt)) totSel++; - } } /* if any points were selected, allocate tSmooth_Bezt points to work on */ @@ -320,7 +313,7 @@ void smooth_fcurve (FCurve *fcu) tsb->h3 = &bezt->vec[2][1]; /* advance to the next tsb to populate */ - if (x < totSel- 1) + if (x < totSel-1) tsb++; else break; @@ -334,10 +327,10 @@ void smooth_fcurve (FCurve *fcu) * - next: w/a ratio = 1:1:2:5:3 */ - /* round 1: calculate previous and next */ + /* round 1: calculate smoothing deltas and new values */ tsb= tarray; for (i=0; i < totSel; i++, tsb++) { - /* don't touch end points (otherwise, curves slowly explode) */ + /* don't touch end points (otherwise, curves slowly explode, as we don't have enough data there) */ if (ELEM(i, 0, (totSel-1)) == 0) { const tSmooth_Bezt *tP1 = tsb - 1; const tSmooth_Bezt *tP2 = (i-2 > 0) ? (tsb - 2) : (NULL); @@ -350,21 +343,26 @@ void smooth_fcurve (FCurve *fcu) const float n1 = *tN1->h2; const float n2 = (tN2) ? (*tN2->h2) : (*tN1->h2); - /* calculate previous and next */ - *tsb->h1= (3*p2 + 5*p1 + 2*c1 + n1 + n2) / 12; - *tsb->h3= (p2 + p1 + 2*c1 + 5*n1 + 3*n2) / 12; + /* calculate previous and next, then new position by averaging these */ + tsb->y1= (3*p2 + 5*p1 + 2*c1 + n1 + n2) / 12; + tsb->y3= (p2 + p1 + 2*c1 + 5*n1 + 3*n2) / 12; + + tsb->y2 = (tsb->y1 + tsb->y3) / 2; } } - /* round 2: calculate new values and reset handles */ + /* round 2: apply new values */ tsb= tarray; for (i=0; i < totSel; i++, tsb++) { - /* calculate new position by averaging handles */ - *tsb->h2 = (*tsb->h1 + *tsb->h3) / 2; - - /* reset handles now */ - *tsb->h1 = *tsb->h2; - *tsb->h3 = *tsb->h2; + /* don't touch end points, as their values were't touched above */ + if (ELEM(i, 0, (totSel-1)) == 0) { + /* y2 takes the average of the 2 points */ + *tsb->h2 = tsb->y2; + + /* handles are weighted between their original values and the averaged values */ + *tsb->h1 = ((*tsb->h1) * 0.7f) + (tsb->y1 * 0.3f); + *tsb->h3 = ((*tsb->h3) * 0.7f) + (tsb->y3 * 0.3f); + } } /* free memory required for tarray */ |