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.
This commit is contained in:
Joshua Leung
2011-03-12 01:09:40 +00:00
parent c786a2c805
commit 80de27914d

View File

@@ -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 */