Follow Path Constraint - "Animate Path" Operator
authorJoshua Leung <aligorith@gmail.com>
Fri, 5 Oct 2012 14:51:35 +0000 (14:51 +0000)
committerJoshua Leung <aligorith@gmail.com>
Fri, 5 Oct 2012 14:51:35 +0000 (14:51 +0000)
Added a convenience operator to the Follow Path constraint which adds a F-Curve
for the path (or the operator's "fixed position" value if no path is assigned),
with options for setting the start frame and length of motion. This makes it
easier for common users to just set up a quick follow-path animation where the
camera (e.g. flying around a set over certain number of frames).

A key advantage of this is that it takes care of the underlying math required
for setting up the generator curve accordingly (I've got some plans for making
this a bit friendlier to use later). Now, animating the paths is a one-click
operation, with the start and length properties able to be controlled using the
operator properties.

release/scripts/startup/bl_ui/properties_object_constraint.py
source/blender/editors/object/object_constraint.c
source/blender/editors/object/object_intern.h
source/blender/editors/object/object_ops.c

index 3d671a0d1b7e11795b31686ac378358b2ac38950..fba7bd8712a28046adb814307c4eb15c27fa737e 100644 (file)
@@ -212,6 +212,7 @@ class ConstraintButtonsPanel():
 
     def FOLLOW_PATH(self, context, layout, con):
         self.target_template(layout, con)
+        layout.operator("constraint.followpath_path_animate", text="Animate Path", icon='ANIM_DATA')
 
         split = layout.split()
 
index 1ef7c12b4095fa999274ff783ea8a5004d988be6..b7aadd3cc74fa696f460ae5f764ccb17e2cf2049 100644 (file)
@@ -40,6 +40,7 @@
 #include "BLI_dynstr.h"
 #include "BLI_utildefines.h"
 
+#include "DNA_anim_types.h"
 #include "DNA_constraint_types.h"
 #include "DNA_curve_types.h"
 #include "DNA_scene_types.h"
@@ -51,6 +52,7 @@
 #include "BKE_constraint.h"
 #include "BKE_context.h"
 #include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
 #include "BKE_global.h"
 #include "BKE_main.h"
 #include "BKE_object.h"
@@ -71,6 +73,7 @@
 
 #include "ED_object.h"
 #include "ED_armature.h"
+#include "ED_keyframing.h"
 #include "ED_screen.h"
 
 #include "UI_interface.h"
@@ -877,6 +880,130 @@ void CONSTRAINT_OT_childof_clear_inverse(wmOperatorType *ot)
        edit_constraint_properties(ot);
 }
 
+/* --------------- Follow Path Constraint ------------------ */
+
+static int followpath_path_animate_exec(bContext *C, wmOperator *op)
+{
+       Object *ob = ED_object_active_context(C);
+       bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_FOLLOWPATH);
+       bFollowPathConstraint *data = (con) ? (bFollowPathConstraint *)con->data : NULL;
+       
+       bAction *act = NULL;
+       FCurve *fcu = NULL;
+       int sfra = RNA_int_get(op->ptr, "frame_start");
+       int len  = RNA_int_get(op->ptr, "length");
+       float standardRange = 1.0;
+       
+       /* nearly impossible sanity check */
+       if (data == NULL) {
+               BKE_report(op->reports, RPT_ERROR, "Follow Path constraint not found");
+               return OPERATOR_CANCELLED;
+       }
+       
+       /* add F-Curve as appropriate */
+       if (data->tar) {
+               Curve *cu = (Curve *)data->tar->data;
+               
+               if ( ELEM(NULL, cu->adt, cu->adt->action) ||
+                       (list_find_fcurve(&cu->adt->action->curves, "eval_time", 0) == NULL))
+               {
+                       /* create F-Curve for path animation */
+                       act = verify_adt_action(&cu->id, 1);
+                       fcu = verify_fcurve(act, NULL, NULL, "eval_time", 0, 1);
+                       
+                       /* standard vertical range - 1:1 = 100 frames */
+                       standardRange = 100.0f;
+               }
+               else {
+                       /* path anim exists already - abort for now as this may well be what was intended */
+                       BKE_report(op->reports, RPT_WARNING, "Path is already animated");
+                       return OPERATOR_CANCELLED;
+               }
+       }
+       else {
+               /* animate constraint's "fixed offset" */
+               PointerRNA ptr;
+               PropertyRNA *prop;
+               char *path;
+               
+               /* get RNA pointer to constraint's "offset_factor" property - to build RNA path */
+               RNA_pointer_create(&ob->id, &RNA_FollowPathConstraint, con, &ptr);
+               prop = RNA_struct_find_property(&ptr, "offset_factor");
+               
+               path = RNA_path_from_ID_to_property(&ptr, prop);
+               
+               /* create F-Curve for constraint */
+               act = verify_adt_action(&ob->id, 1);
+               fcu = verify_fcurve(act, NULL, NULL, path, 0, 1);
+               
+               /* standard vertical range - 0.0 to 1.0 */
+               standardRange = 1.0f;
+               
+               /* enable "Use Fixed Position" so that animating this has effect */
+               data->followflag |= FOLLOWPATH_STATIC;
+               
+               /* path needs to be freed */
+               if (path) 
+                       MEM_freeN(path);
+       }
+       
+       /* setup dummy 'generator' modifier here to get 1-1 correspondence still working
+        * and define basic slope of this curve based on the properties
+        */
+       if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first) {
+               FModifier *fcm = add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR);
+               FMod_Generator *gen = fcm->data;
+               
+               /* Assume that we have the following equation:
+                *     y = Ax + B
+                *         1    0       <-- coefficients array indices
+                */
+               float A = standardRange / (float)(len);
+               float B = (float)(-sfra) * A;
+               
+               gen->coefficients[1] = A;
+               gen->coefficients[0] = B;
+       }
+       
+       /* updates... */
+       WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
+       return OPERATOR_FINISHED;
+}
+
+static int followpath_path_animate_invoke(bContext *C, wmOperator *op, wmEvent *evt)
+{
+       /* hook up invoke properties for figuring out which constraint we're dealing with */
+       if (edit_constraint_invoke_properties(C, op)) {
+               return followpath_path_animate_exec(C, op);
+       }
+       else {
+               return OPERATOR_CANCELLED;
+       }
+}
+
+void CONSTRAINT_OT_followpath_path_animate(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Auto Animate Path";
+       ot->idname = "CONSTRAINT_OT_followpath_path_animate";
+       ot->description = "Add default animation for path used by constraint if it isn't animated already";
+       
+       /* callbacks */
+       ot->invoke = followpath_path_animate_invoke;
+       ot->exec = followpath_path_animate_exec;
+       ot->poll = edit_constraint_poll;
+       
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+       
+       /* props */
+       edit_constraint_properties(ot);
+       RNA_def_int(ot->srna, "frame_start", 1, MINAFRAME, MAXFRAME, "Start Frame", 
+                   "First frame of path animation", MINAFRAME, MAXFRAME);
+       RNA_def_int(ot->srna, "length", 100, 0, MAXFRAME, "Length", 
+                   "Number of frames that path animation should take", 0, MAXFRAME);
+}
+
 /* ------------- Object Solver Constraint ------------------ */
 
 static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op)
index bb288462f0fd7a3974ebac758d41227cce66bcf3..4c83f6ef2ceacc410b1faefe6b434489d517a692 100644 (file)
@@ -194,6 +194,7 @@ void CONSTRAINT_OT_childof_set_inverse(struct wmOperatorType *ot);
 void CONSTRAINT_OT_childof_clear_inverse(struct wmOperatorType *ot);
 void CONSTRAINT_OT_objectsolver_set_inverse(struct wmOperatorType *ot);
 void CONSTRAINT_OT_objectsolver_clear_inverse(struct wmOperatorType *ot);
+void CONSTRAINT_OT_followpath_path_animate(struct wmOperatorType *ot);
 
 /* object_vgroup.c */
 void OBJECT_OT_vertex_group_add(struct wmOperatorType *ot);
index 181a98a8896d133d07eb63226eb095f9d35305ea..fa40d579e2b4582e08103da16b8134de8d716d3c 100644 (file)
@@ -169,6 +169,7 @@ void ED_operatortypes_object(void)
        WM_operatortype_append(CONSTRAINT_OT_childof_clear_inverse);
        WM_operatortype_append(CONSTRAINT_OT_objectsolver_set_inverse);
        WM_operatortype_append(CONSTRAINT_OT_objectsolver_clear_inverse);
+       WM_operatortype_append(CONSTRAINT_OT_followpath_path_animate);
 
        WM_operatortype_append(OBJECT_OT_vertex_group_add);
        WM_operatortype_append(OBJECT_OT_vertex_group_remove);