Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorJoshua Leung <aligorith@gmail.com>2011-03-25 06:58:21 +0300
committerJoshua Leung <aligorith@gmail.com>2011-03-25 06:58:21 +0300
commit16e736b7db3ef3597e22f55e7b26416ee562a418 (patch)
tree7b4d0980e6c33c35aea5b375718add6f84dbb74e /source
parent0c03fa78c10f04283512f2a5a4557d86c72d6f29 (diff)
Graph Editor: Euler Filter ported from Py to C
Ported joeedh's Euler Filter code from Python to C so that this is more in line with the other Graph Editor tools - i.e. joeedh's version only worked on the active bone's curves, while standard tools could work with multiple bones/objects at the same time. To use this new version of this operator: 1) Select all the F-Curves for all 3 of the components (XYZ) for the euler rotations you wish to clean up. In the Graph Editor, they must be one after the other (i.e. you can't have "RotX, RotY, something else, RotZ") 2) Activate the operator from the Key menu in the Graph Editor In an old test file I have floating around, this method did not appear to be good enough to fix a very clear discontinuity in the middle of the action, so I'll test some additional methods too
Diffstat (limited to 'source')
-rw-r--r--source/blender/editors/space_graph/graph_edit.c123
-rw-r--r--source/blender/editors/space_graph/graph_intern.h1
-rw-r--r--source/blender/editors/space_graph/graph_ops.c1
3 files changed, 108 insertions, 17 deletions
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index fdd43aa0566..deffc60019e 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -1501,12 +1501,13 @@ static int graphkeys_handletype_exec(bContext *C, wmOperator *op)
* of values to -180 degrees to 180 degrees.
*/
-#if 0 // XXX this is not ready for the primetime yet
-
/* set of three euler-rotation F-Curves */
typedef struct tEulerFilter {
+ struct tEulerFilter *next, *prev;
+
ID *id; /* ID-block which owns the channels */
- FCurve (*fcurves)[3]; /* 3 Pointers to F-Curves */
+ FCurve *(fcurves[3]); /* 3 Pointers to F-Curves */
+ char *rna_path; /* Pointer to one of the RNA Path's used by one of the F-Curves */
} tEulerFilter;
static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op)
@@ -1518,7 +1519,8 @@ static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op)
int filter;
ListBase eulers = {NULL, NULL};
- tEulerFilter *euf= NULL;
+ tEulerFilter *euf= NULL;
+ int groups=0, failed=0;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -1528,7 +1530,7 @@ static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op)
* 1) Sets of three related rotation curves are identified from the selected channels,
* and are stored as a single 'operation unit' for the next step
* 2) Each set of three F-Curves is processed for each keyframe, with the values being
- * processed according to one of several ways.
+ * processed as necessary
*/
/* step 1: extract only the rotation f-curves */
@@ -1542,45 +1544,134 @@ static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op)
* - only rotation curves
* - for pchan curves, make sure we're only using the euler curves
*/
- if (strstr(fcu->rna_path, "rotation_euler") == 0)
+ if (strstr(fcu->rna_path, "rotation_euler") == NULL)
continue;
+ else if (ELEM3(fcu->array_index, 0, 1, 2) == 0) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Euler Rotation F-Curve has invalid index (ID='%s', Path='%s', Index=%d)",
+ (ale->id)? ale->id->name:"<No ID>", fcu->rna_path, fcu->array_index);
+ continue;
+ }
- /* check if current set of 3-curves is suitable to add this curve to
- * - things like whether the current set of curves is 'full' should be checked later only
- * - first check if id-blocks are compatible
+ /* optimisation: assume that xyz curves will always be stored consecutively,
+ * so if the paths or the ID's don't match up, then a curve needs to be added
+ * to a new group
*/
- if ((euf) && (ale->id != euf->id)) {
- /* if the paths match, add this curve to the set of curves */
- // NOTE: simple string compare for now... could be a bit more fancy...
-
+ if ((euf) && (euf->id == ale->id) && (strcmp(euf->rna_path, fcu->rna_path)==0)) {
+ /* this should be fine to add to the existing group then */
+ euf->fcurves[fcu->array_index]= fcu;
}
else {
/* just add to a new block */
euf= MEM_callocN(sizeof(tEulerFilter), "tEulerFilter");
BLI_addtail(&eulers, euf);
+ groups++;
euf->id= ale->id;
+ euf->rna_path = fcu->rna_path; /* this should be safe, since we're only using it for a short time */
euf->fcurves[fcu->array_index]= fcu;
}
}
BLI_freelistN(&anim_data);
+ if (groups == 0) {
+ BKE_report(op->reports, RPT_WARNING, "No Euler Rotation F-Curves to fix up");
+ return OPERATOR_CANCELLED;
+ }
+
/* step 2: go through each set of curves, processing the values at each keyframe
* - it is assumed that there must be a full set of keyframes at each keyframe position
*/
for (euf= eulers.first; euf; euf= euf->next) {
+ int f;
+
+ /* sanity check: ensure that there are enough F-Curves to work on in this group */
+ // TODO: also enforce assumption that there be a full set of keyframes at each position by ensuring that totvert counts are same?
+ if (ELEM3(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) {
+ /* report which components are missing */
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Missing %s%s%s component(s) of euler rotation for ID='%s' and RNA-Path='%s'",
+ (euf->fcurves[0]==NULL)? "X":"",
+ (euf->fcurves[1]==NULL)? "Y":"",
+ (euf->fcurves[2]==NULL)? "Z":"",
+ euf->id->name, euf->rna_path);
+
+ /* keep track of number of failed sets, and carry on to next group */
+ failed++;
+ continue;
+ }
+ /* simple method: just treat any difference between keys of greater than 180 degrees as being a flip */
+ // FIXME: there are more complicated methods that will be needed to fix more cases than just some
+ for (f = 0; f < 3; f++) {
+ FCurve *fcu = euf->fcurves[f];
+ BezTriple *bezt, *prev=NULL;
+ unsigned int i;
+
+ /* skip if not enough vets to do a decent analysis of... */
+ if (fcu->totvert <= 2)
+ continue;
+
+ /* prev follows bezt, bezt = "current" point to be fixed */
+ for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, prev=bezt, bezt++) {
+ /* our method depends on determining a "difference" from the previous vert */
+ if (prev == NULL)
+ continue;
+
+ /* > 180 degree flip? */
+ if (fabs(prev->vec[1][1] - bezt->vec[1][1]) >= M_PI) {
+ /* 360 degrees to add/subtract frame value until difference is acceptably small that there's no more flip */
+ const double fac = 2.0 * M_PI;
+
+ if (prev->vec[1][1] > bezt->vec[1][1]) {
+ while (fabs(bezt->vec[1][1] - prev->vec[1][1]) >= M_PI) {
+ bezt->vec[0][1] += fac;
+ bezt->vec[1][1] += fac;
+ bezt->vec[2][1] += fac;
+ }
+ }
+ else /* if (prev->vec[1][1] < bezt->vec[1][1]) */ {
+ while (fabs(bezt->vec[1][1] - prev->vec[1][1]) >= M_PI) {
+ bezt->vec[0][1] -= fac;
+ bezt->vec[1][1] -= fac;
+ bezt->vec[2][1] -= fac;
+ }
+ }
+ }
+ }
+ }
}
BLI_freelistN(&eulers);
- return OPERATOR_FINISHED;
+ /* updates + finishing warnings */
+ if (failed == groups) {
+ BKE_report(op->reports, RPT_ERROR,
+ "No Euler Rotations could be corrected. Ensure each rotation has keys for all components, and that F-Curves for these are in consecutive XYZ order and selected.");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ if (failed) {
+ BKE_report(op->reports, RPT_ERROR,
+ "Some Euler Rotations couldn't be corrected due to missing/unselected/out-of-order F-Curves. Ensure each rotation has keys for all components, and that F-Curves for these are in consecutive XYZ order and selected.");
+ }
+
+ /* validate keyframes after editing */
+ ANIM_editkeyframes_refresh(&ac);
+
+ /* set notifier that keyframes have changed */
+ WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
+
+ /* done at last */
+ return OPERATOR_FINISHED;
+ }
}
void GRAPH_OT_euler_filter (wmOperatorType *ot)
{
/* identifiers */
- ot->name= "Euler Filter";
+ ot->name= "Euler Discontinuity Filter";
ot->idname= "GRAPH_OT_euler_filter";
+ ot->description= "Fixes the most common causes of gimbal lock in the selected Euler Rotation F-Curves";
/* api callbacks */
ot->exec= graphkeys_euler_filter_exec;
@@ -1590,8 +1681,6 @@ void GRAPH_OT_euler_filter (wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
-#endif // XXX this is not ready for the primetime yet
-
/* ***************** Jump to Selected Frames Operator *********************** */
/* snap current-frame indicator to 'average time' of selected keyframe */
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index feb17827db7..2aefb7c64dd 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -111,6 +111,7 @@ void GRAPH_OT_sample(struct wmOperatorType *ot);
void GRAPH_OT_bake(struct wmOperatorType *ot);
void GRAPH_OT_sound_bake(struct wmOperatorType *ot);
void GRAPH_OT_smooth(struct wmOperatorType *ot);
+void GRAPH_OT_euler_filter(struct wmOperatorType *ot);
void GRAPH_OT_handle_type(struct wmOperatorType *ot);
void GRAPH_OT_interpolation_type(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 674d2809188..e75fbeb8efc 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -255,6 +255,7 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_sound_bake);
WM_operatortype_append(GRAPH_OT_smooth);
WM_operatortype_append(GRAPH_OT_clean);
+ WM_operatortype_append(GRAPH_OT_euler_filter);
WM_operatortype_append(GRAPH_OT_delete);
WM_operatortype_append(GRAPH_OT_duplicate);