From f8362836a5c8feff3715ca823025caba249208c2 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Wed, 4 Sep 2019 14:59:18 +0300 Subject: Copy Transforms: add a mixing mode option. Allow combining location, rotation and scale at the same time, using one constraint. The mixing modes are based on matrix multiplication, but handle scale in a way that avoids creating shear. Reviewers: brecht Differential Revision: https://developer.blender.org/D5640 --- .../scripts/startup/bl_ui/properties_constraint.py | 2 ++ source/blender/blenkernel/intern/constraint.c | 36 ++++++++++++++++++++-- .../blender/editors/transform/transform_convert.c | 9 ++++++ source/blender/makesdna/DNA_constraint_types.h | 12 ++++++++ source/blender/makesrna/intern/rna_constraint.c | 29 +++++++++++++++++ 5 files changed, 85 insertions(+), 3 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index ac1ebedeba4..df53fccf9ea 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -459,6 +459,8 @@ class ConstraintButtonsPanel: def COPY_TRANSFORMS(self, _context, layout, con): self.target_template(layout, con) + layout.prop(con, "mix_mode", text="Mix") + self.space_template(layout, con) # def SCRIPT(self, context, layout, con): diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 803aae76422..317973cc0c1 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -2090,13 +2090,43 @@ static void translike_flush_tars(bConstraint *con, ListBase *list, bool no_copy) } } -static void translike_evaluate(bConstraint *UNUSED(con), bConstraintOb *cob, ListBase *targets) +static void translike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets) { + bTransLikeConstraint *data = con->data; bConstraintTarget *ct = targets->first; if (VALID_CONS_TARGET(ct)) { - /* just copy the entire transform matrix of the target */ - copy_m4_m4(cob->matrix, ct->matrix); + if (data->mix_mode == TRANSLIKE_MIX_REPLACE) { + /* just copy the entire transform matrix of the target */ + copy_m4_m4(cob->matrix, ct->matrix); + } + else { + float old_loc[3], old_rot[3][3], old_size[3]; + float new_loc[3], new_rot[3][3], new_size[3]; + + /* Separate matrices so they can be combined in a way that avoids shear. */ + mat4_to_loc_rot_size(old_loc, old_rot, old_size, cob->matrix); + mat4_to_loc_rot_size(new_loc, new_rot, new_size, ct->matrix); + + switch (data->mix_mode) { + case TRANSLIKE_MIX_BEFORE: + mul_v3_m4v3(new_loc, ct->matrix, old_loc); + mul_m3_m3m3(new_rot, new_rot, old_rot); + mul_v3_v3(new_size, old_size); + break; + + case TRANSLIKE_MIX_AFTER: + mul_v3_m4v3(new_loc, cob->matrix, new_loc); + mul_m3_m3m3(new_rot, old_rot, new_rot); + mul_v3_v3(new_size, old_size); + break; + + default: + BLI_assert(false); + } + + loc_rot_size_to_mat4(cob->matrix, new_loc, new_rot, new_size); + } } } diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 14eee2318cd..cbb291414bf 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -1335,6 +1335,15 @@ bool constraints_list_needinv(TransInfo *t, ListBase *list) return true; } } + else if (con->type == CONSTRAINT_TYPE_TRANSLIKE) { + /* Copy Transforms constraint only does this in the Before mode. */ + bTransLikeConstraint *data = (bTransLikeConstraint *)con->data; + + if (ELEM(data->mix_mode, TRANSLIKE_MIX_BEFORE) && + ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION)) { + return true; + } + } else if (con->type == CONSTRAINT_TYPE_TRANSFORM) { /* Transform constraint needs it for rotation at least (r.57309), * but doing so when translating may also mess things up [#36203] diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index a7f900ddc9b..d123cf21db9 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -307,6 +307,8 @@ typedef struct bSameVolumeConstraint { /* Copy Transform Constraint */ typedef struct bTransLikeConstraint { struct Object *tar; + char mix_mode; + char _pad[7]; /** MAX_ID_NAME-2. */ char subtarget[64]; } bTransLikeConstraint; @@ -790,6 +792,16 @@ typedef enum eCopyScale_Flags { SIZELIKE_UNIFORM = (1 << 5), } eCopyScale_Flags; +/* bTransLikeConstraint.mix_mode */ +typedef enum eCopyTransforms_MixMode { + /* Replace rotation channel values. */ + TRANSLIKE_MIX_REPLACE = 0, + /* Multiply the copied transformation on the left, with anti-shear scale handling. */ + TRANSLIKE_MIX_BEFORE, + /* Multiply the copied transformation on the right, with anti-shear scale handling. */ + TRANSLIKE_MIX_AFTER, +} eCopyTransforms_MixMode; + /* bTransformConstraint.to/from */ typedef enum eTransform_ToFrom { TRANS_LOCATION = 0, diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 79e38717569..658addece8a 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -1515,6 +1515,28 @@ static void rna_def_constraint_same_volume(BlenderRNA *brna) static void rna_def_constraint_transform_like(BlenderRNA *brna) { StructRNA *srna; + PropertyRNA *prop; + + static const EnumPropertyItem mix_mode_items[] = { + {TRANSLIKE_MIX_REPLACE, + "REPLACE", + 0, + "Replace", + "Replace the original transformation with copied"}, + {TRANSLIKE_MIX_BEFORE, + "BEFORE", + 0, + "Before Original", + "Apply copied transformation before original, as if the constraint target is a parent. " + "Scale is handled specially to avoid creating shear"}, + {TRANSLIKE_MIX_AFTER, + "AFTER", + 0, + "After Original", + "Apply copied transformation after original, as if the constraint target is a child. " + "Scale is handled specially to avoid creating shear"}, + {0, NULL, 0, NULL, NULL}, + }; srna = RNA_def_struct(brna, "CopyTransformsConstraint", "Constraint"); RNA_def_struct_ui_text( @@ -1527,6 +1549,13 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna) RNA_def_struct_ui_icon(srna, ICON_CON_TRANSLIKE); rna_def_constraint_target_common(srna); + + prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "mix_mode"); + RNA_def_property_enum_items(prop, mix_mode_items); + RNA_def_property_ui_text( + prop, "Mix Mode", "Specify how the copied and existing transformations are combined"); + RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); } static void rna_def_constraint_minmax(BlenderRNA *brna) -- cgit v1.2.3