diff options
author | Chris Clyne <lateasusual> | 2020-09-16 16:52:43 +0300 |
---|---|---|
committer | Sebastian Parborg <darkdefende@gmail.com> | 2020-09-16 16:55:22 +0300 |
commit | c9c0f893073300d6898114cfc6cacd563c630750 (patch) | |
tree | 2f7b102728debdddd1b9f968886e90d39ac00c1a | |
parent | 569e2e6dbac489b4143859cfeb87debf7253eab6 (diff) |
Action Constraint: Add manual time factor input control
Adds an optional slider to the action constraint so that it can be
driven without a constraint target.
This is very helpful for more complex rigging and mechanical rigs, as it
means the action constraint can be controlled with a driver/custom
property directly, currently if we want to use a driver to control it we
must add a "dummy" bone/object inbetween to act as a control.
Reviewed By: Sebastian Parborg, Sybren A. Stüvel, Demeter Dzadik, Julian Eisel
Differential Revision: http://developer.blender.org/D8022
-rw-r--r-- | release/scripts/startup/bl_ui/properties_constraint.py | 26 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/constraint.c | 76 | ||||
-rw-r--r-- | source/blender/editors/object/object_constraint.c | 5 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_constraint_types.h | 5 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_constraint.c | 15 |
5 files changed, 84 insertions, 43 deletions
diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index da35ea680b8..14619ef916d 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -508,7 +508,18 @@ class ConstraintButtonsPanel(Panel): layout.use_property_split = True layout.use_property_decorate = True - self.target_template(layout, con) + target_row = layout.row(align=True) + target_row.active = not con.use_eval_time + self.target_template(target_row, con) + + row = layout.row(align=True, heading="Evaluation Time") + row.use_property_decorate = False + sub = row.row(align=True) + sub.prop(con, "use_eval_time", text="") + subsub = sub.row(align=True) + subsub.active = con.use_eval_time + subsub.prop(con, "eval_time", text="") + row.prop_decorator(con, "eval_time") layout.prop(con, "mix_mode", text="Mix") @@ -1105,13 +1116,14 @@ class ConstraintButtonsSubPanel(Panel): layout.use_property_split = True layout.use_property_decorate = True - layout.prop(con, "transform_channel", text="Channel") - layout.prop(con, "target_space") - - col = layout.column(align=True) - col.prop(con, "min", text="Range Min") - col.prop(con, "max", text="Max") + col = layout.column() + col.active = not con.use_eval_time + col.prop(con, "transform_channel", text="Channel") + col.prop(con, "target_space") + sub = col.column(align=True) + sub.prop(con, "min", text="Range Min") + sub.prop(con, "max", text="Max") def draw_action_action(self, context): layout = self.layout diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index fc1b4d82c20..9411f937f08 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -2634,7 +2634,7 @@ static void actcon_get_tarmat(struct Depsgraph *depsgraph, { bActionConstraint *data = con->data; - if (VALID_CONS_TARGET(ct)) { + if (VALID_CONS_TARGET(ct) || data->flag & ACTCON_USE_EVAL_TIME) { float tempmat[4][4], vec[3]; float s, t; short axis; @@ -2642,42 +2642,48 @@ static void actcon_get_tarmat(struct Depsgraph *depsgraph, /* initialize return matrix */ unit_m4(ct->matrix); - /* get the transform matrix of the target */ - constraint_target_to_mat4(ct->tar, - ct->subtarget, - tempmat, - CONSTRAINT_SPACE_WORLD, - ct->space, - con->flag, - con->headtail); + /* Skip targets if we're using local float property to set action time */ + if (data->flag & ACTCON_USE_EVAL_TIME) { + s = data->eval_time; + } else { + /* get the transform matrix of the target */ + constraint_target_to_mat4(ct->tar, + ct->subtarget, + tempmat, + CONSTRAINT_SPACE_WORLD, + ct->space, + con->flag, + con->headtail); + + /* determine where in transform range target is */ + /* data->type is mapped as follows for backwards compatibility: + * 00,01,02 - rotation (it used to be like this) + * 10,11,12 - scaling + * 20,21,22 - location + */ + if (data->type < 10) { + /* extract rotation (is in whatever space target should be in) */ + mat4_to_eul(vec, tempmat); + mul_v3_fl(vec, RAD2DEGF(1.0f)); /* rad -> deg */ + axis = data->type; + } + else if (data->type < 20) { + /* extract scaling (is in whatever space target should be in) */ + mat4_to_size(vec, tempmat); + axis = data->type - 10; + } + else { + /* extract location */ + copy_v3_v3(vec, tempmat[3]); + axis = data->type - 20; + } - /* determine where in transform range target is */ - /* data->type is mapped as follows for backwards compatibility: - * 00,01,02 - rotation (it used to be like this) - * 10,11,12 - scaling - * 20,21,22 - location - */ - if (data->type < 10) { - /* extract rotation (is in whatever space target should be in) */ - mat4_to_eul(vec, tempmat); - mul_v3_fl(vec, RAD2DEGF(1.0f)); /* rad -> deg */ - axis = data->type; - } - else if (data->type < 20) { - /* extract scaling (is in whatever space target should be in) */ - mat4_to_size(vec, tempmat); - axis = data->type - 10; - } - else { - /* extract location */ - copy_v3_v3(vec, tempmat[3]); - axis = data->type - 20; - } + BLI_assert((unsigned int)axis < 3); - BLI_assert((unsigned int)axis < 3); + /* Target defines the animation */ + s = (vec[axis] - data->min) / (data->max - data->min); + } - /* Target defines the animation */ - s = (vec[axis] - data->min) / (data->max - data->min); CLAMP(s, 0, 1); t = (s * (data->end - data->start)) + data->start; const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph, @@ -2734,7 +2740,7 @@ static void actcon_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targ bActionConstraint *data = con->data; bConstraintTarget *ct = targets->first; - if (VALID_CONS_TARGET(ct)) { + if (VALID_CONS_TARGET(ct) || data->flag & ACTCON_USE_EVAL_TIME) { switch (data->mix_mode) { case ACTCON_MIX_BEFORE: mul_m4_m4m4_aligned_scale(cob->matrix, ct->matrix, cob->matrix); diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index b062ae0c698..af04c4a3263 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -387,6 +387,11 @@ static void test_constraint( data->act = NULL; con->flag |= CONSTRAINT_DISABLE; } + + /* Skip target checking if we're not using it */ + if (data->flag & ACTCON_USE_EVAL_TIME) { + check_targets = false; + } } else if (con->type == CONSTRAINT_TYPE_FOLLOWPATH) { bFollowPathConstraint *data = con->data; diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index cddc78d7640..92ee3f062a6 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -337,7 +337,8 @@ typedef struct bActionConstraint { float max; int flag; char mix_mode; - char _pad[7]; + char _pad[3]; + float eval_time; /* Only used when flag ACTCON_USE_EVAL_TIME is set. */ struct bAction *act; /** MAX_ID_NAME-2. */ char subtarget[64]; @@ -860,6 +861,8 @@ typedef enum eSameVolume_Mode { typedef enum eActionConstraint_Flags { /* Bones use "object" part of target action, instead of "same bone name" part */ ACTCON_BONE_USE_OBJECT_ACTION = (1 << 0), + /* Ignore the transform of 'tar' and use 'eval_time' instead: */ + ACTCON_USE_EVAL_TIME = (1 << 1), } eActionConstraint_Flags; /* bActionConstraint.mix_mode */ diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index d9dd35c4280..653056e4dc1 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -1790,6 +1790,21 @@ static void rna_def_constraint_action(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); RNA_def_property_float_funcs(prop, NULL, NULL, "rna_ActionConstraint_minmax_range"); + prop = RNA_def_property(srna, "eval_time", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "eval_time"); + RNA_def_property_range(prop, 0.f, 1.f); + RNA_def_property_ui_text( + prop, "Evaluation Time", "Interpolates between Action Start and End frames"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + prop = RNA_def_property(srna, "use_eval_time", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ACTCON_USE_EVAL_TIME); + RNA_def_property_ui_text(prop, + "Use Evaluation Time", + "Interpolate between Action Start and End frames, with the Evaluation " + "Time slider instead of the Target object/bone"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + RNA_define_lib_overridable(false); } |