Compare commits

...

2 Commits

Author SHA1 Message Date
db24fc4f27 Copy Transforms: implement invert and split mode options.
Add new options to invert the matrix, and a enum selecting whether
to handle the transformation as an opaque matrix, split off scale
to avoid shear, or do a full separation into loc/rot/scale as
a simple replacement for a sequence of three Copy constraints.

In addition, split modes other than no split remove shear from
the target transformation before starting the processing.
2020-09-21 01:49:34 +03:00
71b595fc0e Constraints: add Absolute and Owner Local Space support.
Add two new transformation space choices for bone constraints, which
represent the local transformation of the bone either in world or in
the constraint owner local space.

The use case for this is transferring the local (i.e. excluding the
effect of parents) transformation of one bone to another one, while
ignoring the difference between their rest pose orientations.
The transfer can be achieved by either Abs->Abs or Owner->Local pairs,
but the latter works better with the shear avoiding constraint math.

Absolute Local Space replaces the following setup:

* A `child` bone of the `target`, with zero rest rotation in pose space.
* A `sibling` bone of the `target`, positioned same as `child` in rest
  pose and using Copy Transforms in World Space from `child`.
* The `owner` bone constraint uses Local Space of `sibling`.

Owner Local Space replaces the following setup:

* A `child` bone of the `target`, rotated the same as `owner` in rest pose.
* A `sibling` bone of the `target`, positioned same as `child` in rest
  pose and using Copy Transforms in World Space from `child`.
* The `owner` bone constraint uses Local Space of `sibling`.
2020-09-21 01:40:12 +03:00
9 changed files with 286 additions and 51 deletions

View File

@@ -496,6 +496,8 @@ class ConstraintButtonsPanel(Panel):
self.target_template(layout, con) self.target_template(layout, con)
layout.prop(con, "invert")
layout.prop(con, "split_mode", text="Components")
layout.prop(con, "mix_mode", text="Mix") layout.prop(con, "mix_mode", text="Mix")
self.space_template(layout, con) self.space_template(layout, con)

View File

@@ -198,6 +198,7 @@ void BKE_constraints_clear_evalob(struct bConstraintOb *cob);
void BKE_constraint_mat_convertspace(struct Object *ob, void BKE_constraint_mat_convertspace(struct Object *ob,
struct bPoseChannel *pchan, struct bPoseChannel *pchan,
float mat[4][4], float mat[4][4],
bConstraintOb *cob,
short from, short from,
short to, short to,
const bool keep_scale); const bool keep_scale);

View File

@@ -255,8 +255,13 @@ void BKE_constraints_clear_evalob(bConstraintOb *cob)
* of a matrix from one space to another for constraint evaluation. * of a matrix from one space to another for constraint evaluation.
* For now, this is only implemented for Objects and PoseChannels. * For now, this is only implemented for Objects and PoseChannels.
*/ */
void BKE_constraint_mat_convertspace( void BKE_constraint_mat_convertspace(Object *ob,
Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to, const bool keep_scale) bPoseChannel *pchan,
float mat[4][4],
bConstraintOb *cob,
short from,
short to,
const bool keep_scale)
{ {
float diff_mat[4][4]; float diff_mat[4][4];
float imat[4][4]; float imat[4][4];
@@ -281,9 +286,10 @@ void BKE_constraint_mat_convertspace(
mul_m4_m4m4(mat, imat, mat); mul_m4_m4m4(mat, imat, mat);
/* use pose-space as stepping stone for other spaces... */ /* use pose-space as stepping stone for other spaces... */
if (ELEM(to, CONSTRAINT_SPACE_LOCAL, CONSTRAINT_SPACE_PARLOCAL)) { if (to != CONSTRAINT_SPACE_POSE) {
/* call self with slightly different values */ /* call self with slightly different values */
BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); BKE_constraint_mat_convertspace(
ob, pchan, mat, cob, CONSTRAINT_SPACE_POSE, to, keep_scale);
} }
break; break;
} }
@@ -294,9 +300,25 @@ void BKE_constraint_mat_convertspace(
mul_m4_m4m4(mat, ob->obmat, mat); mul_m4_m4m4(mat, ob->obmat, mat);
} }
/* pose to local */ /* pose to local */
else if (to == CONSTRAINT_SPACE_LOCAL) { else if (ELEM(to,
CONSTRAINT_SPACE_LOCAL,
CONSTRAINT_SPACE_ABSLOCAL,
CONSTRAINT_SPACE_OWNLOCAL)) {
if (pchan->bone) { if (pchan->bone) {
BKE_armature_mat_pose_to_bone(pchan, mat, mat); BKE_armature_mat_pose_to_bone(pchan, mat, mat);
if (to != CONSTRAINT_SPACE_LOCAL) {
copy_m4_m4(diff_mat, pchan->bone->arm_mat);
if (to == CONSTRAINT_SPACE_OWNLOCAL && cob && cob->pchan && cob->pchan->bone) {
invert_m4_m4(imat, cob->pchan->bone->arm_mat);
mul_m4_m4m4(diff_mat, imat, diff_mat);
}
zero_v3(diff_mat[3]);
invert_m4_m4(imat, diff_mat);
mul_m4_series(mat, diff_mat, mat, imat);
}
} }
} }
/* pose to local with parent */ /* pose to local with parent */
@@ -309,17 +331,32 @@ void BKE_constraint_mat_convertspace(
break; break;
} }
case CONSTRAINT_SPACE_LOCAL: /* ------------ FROM LOCALSPACE --------- */ case CONSTRAINT_SPACE_LOCAL: /* ------------ FROM LOCALSPACE --------- */
{ case CONSTRAINT_SPACE_ABSLOCAL:
case CONSTRAINT_SPACE_OWNLOCAL: {
/* local to pose - do inverse procedure that was done for pose to local */ /* local to pose - do inverse procedure that was done for pose to local */
if (pchan->bone) { if (pchan->bone) {
if (from != CONSTRAINT_SPACE_LOCAL) {
copy_m4_m4(diff_mat, pchan->bone->arm_mat);
if (from == CONSTRAINT_SPACE_OWNLOCAL && cob && cob->pchan && cob->pchan->bone) {
invert_m4_m4(imat, cob->pchan->bone->arm_mat);
mul_m4_m4m4(diff_mat, imat, diff_mat);
}
zero_v3(diff_mat[3]);
invert_m4_m4(imat, diff_mat);
mul_m4_series(mat, imat, mat, diff_mat);
}
/* we need the posespace_matrix = local_matrix + (parent_posespace_matrix + restpos) */ /* we need the posespace_matrix = local_matrix + (parent_posespace_matrix + restpos) */
BKE_armature_mat_bone_to_pose(pchan, mat, mat); BKE_armature_mat_bone_to_pose(pchan, mat, mat);
} }
/* use pose-space as stepping stone for other spaces */ /* use pose-space as stepping stone for other spaces */
if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL)) { if (to != CONSTRAINT_SPACE_POSE) {
/* call self with slightly different values */ /* call self with slightly different values */
BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); BKE_constraint_mat_convertspace(
ob, pchan, mat, cob, CONSTRAINT_SPACE_POSE, to, keep_scale);
} }
break; break;
} }
@@ -331,9 +368,10 @@ void BKE_constraint_mat_convertspace(
} }
/* use pose-space as stepping stone for other spaces */ /* use pose-space as stepping stone for other spaces */
if (ELEM(to, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) { if (to != CONSTRAINT_SPACE_POSE) {
/* call self with slightly different values */ /* call self with slightly different values */
BKE_constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to, keep_scale); BKE_constraint_mat_convertspace(
ob, pchan, mat, cob, CONSTRAINT_SPACE_POSE, to, keep_scale);
} }
break; break;
} }
@@ -568,6 +606,7 @@ static void contarget_get_lattice_mat(Object *ob, const char *substring, float m
static void constraint_target_to_mat4(Object *ob, static void constraint_target_to_mat4(Object *ob,
const char *substring, const char *substring,
float mat[4][4], float mat[4][4],
bConstraintOb *cob,
short from, short from,
short to, short to,
short flag, short flag,
@@ -576,7 +615,7 @@ static void constraint_target_to_mat4(Object *ob,
/* Case OBJECT */ /* Case OBJECT */
if (substring[0] == '\0') { if (substring[0] == '\0') {
copy_m4_m4(mat, ob->obmat); copy_m4_m4(mat, ob->obmat);
BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); BKE_constraint_mat_convertspace(ob, NULL, mat, cob, from, to, false);
} }
/* Case VERTEXGROUP */ /* Case VERTEXGROUP */
/* Current method just takes the average location of all the points in the /* Current method just takes the average location of all the points in the
@@ -589,11 +628,11 @@ static void constraint_target_to_mat4(Object *ob,
*/ */
else if (ob->type == OB_MESH) { else if (ob->type == OB_MESH) {
contarget_get_mesh_mat(ob, substring, mat); contarget_get_mesh_mat(ob, substring, mat);
BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); BKE_constraint_mat_convertspace(ob, NULL, mat, cob, from, to, false);
} }
else if (ob->type == OB_LATTICE) { else if (ob->type == OB_LATTICE) {
contarget_get_lattice_mat(ob, substring, mat); contarget_get_lattice_mat(ob, substring, mat);
BKE_constraint_mat_convertspace(ob, NULL, mat, from, to, false); BKE_constraint_mat_convertspace(ob, NULL, mat, cob, from, to, false);
} }
/* Case BONE */ /* Case BONE */
else { else {
@@ -656,7 +695,7 @@ static void constraint_target_to_mat4(Object *ob,
} }
/* convert matrix space as required */ /* convert matrix space as required */
BKE_constraint_mat_convertspace(ob, pchan, mat, from, to, false); BKE_constraint_mat_convertspace(ob, pchan, mat, cob, from, to, false);
} }
} }
@@ -699,7 +738,7 @@ static bConstraintTypeInfo CTI_CONSTRNAME = {
*/ */
static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph), static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
bConstraint *con, bConstraint *con,
bConstraintOb *UNUSED(cob), bConstraintOb *cob,
bConstraintTarget *ct, bConstraintTarget *ct,
float UNUSED(ctime)) float UNUSED(ctime))
{ {
@@ -707,6 +746,7 @@ static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
constraint_target_to_mat4(ct->tar, constraint_target_to_mat4(ct->tar,
ct->subtarget, ct->subtarget,
ct->matrix, ct->matrix,
cob,
CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_WORLD,
ct->space, ct->space,
con->flag, con->flag,
@@ -721,7 +761,7 @@ static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
*/ */
static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph), static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph),
bConstraint *con, bConstraint *con,
bConstraintOb *UNUSED(cob), bConstraintOb *cob,
bConstraintTarget *ct, bConstraintTarget *ct,
float UNUSED(ctime)) float UNUSED(ctime))
{ {
@@ -729,6 +769,7 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph),
constraint_target_to_mat4(ct->tar, constraint_target_to_mat4(ct->tar,
ct->subtarget, ct->subtarget,
ct->matrix, ct->matrix,
cob,
CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_WORLD,
ct->space, ct->space,
con->flag | CONSTRAINT_BBONE_SHAPE_FULL, con->flag | CONSTRAINT_BBONE_SHAPE_FULL,
@@ -1257,6 +1298,7 @@ static void kinematic_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
constraint_target_to_mat4(ct->tar, constraint_target_to_mat4(ct->tar,
ct->subtarget, ct->subtarget,
ct->matrix, ct->matrix,
cob,
CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_WORLD,
ct->space, ct->space,
con->flag, con->flag,
@@ -2106,21 +2148,108 @@ static void translike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
bConstraintTarget *ct = targets->first; bConstraintTarget *ct = targets->first;
if (VALID_CONS_TARGET(ct)) { if (VALID_CONS_TARGET(ct)) {
switch (data->mix_mode) { float mat[4][4], scale[3];
case TRANSLIKE_MIX_REPLACE: copy_m4_m4(mat, ct->matrix);
copy_m4_m4(cob->matrix, ct->matrix);
break;
case TRANSLIKE_MIX_BEFORE: switch (data->split_mode) {
mul_m4_m4m4_aligned_scale(cob->matrix, ct->matrix, cob->matrix); case TRANSLIKE_SPLIT_NONE: {
break; if (data->flag & TRANSLIKE_INVERT) {
invert_m4(mat);
}
case TRANSLIKE_MIX_AFTER: switch (data->mix_mode) {
mul_m4_m4m4_aligned_scale(cob->matrix, cob->matrix, ct->matrix); case TRANSLIKE_MIX_REPLACE:
copy_m4_m4(cob->matrix, mat);
break;
case TRANSLIKE_MIX_BEFORE:
mul_m4_m4m4(cob->matrix, mat, cob->matrix);
break;
case TRANSLIKE_MIX_AFTER:
mul_m4_m4m4(cob->matrix, cob->matrix, mat);
break;
default:
BLI_assert(!"Unknown Copy Transforms mix mode");
}
break; break;
}
case TRANSLIKE_SPLIT_SCALE: {
orthogonalize_m4_stable(mat, 1, false);
if (data->flag & TRANSLIKE_INVERT) {
normalize_m4_ex(mat, scale);
invert_m4(mat);
invert_v3(scale);
rescale_m4(mat, scale);
}
switch (data->mix_mode) {
case TRANSLIKE_MIX_REPLACE:
copy_m4_m4(cob->matrix, mat);
break;
case TRANSLIKE_MIX_BEFORE:
mul_m4_m4m4_aligned_scale(cob->matrix, mat, cob->matrix);
break;
case TRANSLIKE_MIX_AFTER:
mul_m4_m4m4_aligned_scale(cob->matrix, cob->matrix, mat);
break;
default:
BLI_assert(!"Unknown Copy Transforms mix mode");
}
break;
}
case TRANSLIKE_SPLIT_ALL: {
float loc_a[3], rot_a[3][3], size_a[3];
float loc_b[3], rot_b[3][3], size_b[3];
float loc_r[3], rot_r[3][3], size_r[3];
orthogonalize_m4_stable(mat, 1, false);
mat4_to_loc_rot_size(loc_a, rot_a, size_a, cob->matrix);
mat4_to_loc_rot_size(loc_b, rot_b, size_b, mat);
if (data->flag & TRANSLIKE_INVERT) {
negate_v3(loc_b);
invert_m3(rot_b);
invert_v3(size_b);
}
switch (data->mix_mode) {
case TRANSLIKE_MIX_REPLACE:
copy_v3_v3(loc_r, loc_b);
copy_m3_m3(rot_r, rot_b);
copy_v3_v3(size_r, size_b);
break;
case TRANSLIKE_MIX_BEFORE:
add_v3_v3v3(loc_r, loc_a, loc_b);
mul_m3_m3m3_uniq(rot_r, rot_b, rot_a);
mul_v3_v3v3(size_r, size_a, size_b);
break;
case TRANSLIKE_MIX_AFTER:
add_v3_v3v3(loc_r, loc_a, loc_b);
mul_m3_m3m3_uniq(rot_r, rot_a, rot_b);
mul_v3_v3v3(size_r, size_a, size_b);
break;
default:
BLI_assert(!"Unknown Copy Transforms mix mode");
}
loc_rot_size_to_mat4(cob->matrix, loc_r, rot_r, size_r);
break;
}
default: default:
BLI_assert(!"Unknown Copy Transforms mix mode"); BLI_assert(!"Unknown Copy Transforms split mode");
} }
} }
} }
@@ -2271,7 +2400,7 @@ static void pycon_id_looper(bConstraint *con, ConstraintIDFunc func, void *userd
/* Whether this approach is maintained remains to be seen (aligorith) */ /* Whether this approach is maintained remains to be seen (aligorith) */
static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph), static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
bConstraint *con, bConstraint *con,
bConstraintOb *UNUSED(cob), bConstraintOb *cob,
bConstraintTarget *ct, bConstraintTarget *ct,
float UNUSED(ctime)) float UNUSED(ctime))
{ {
@@ -2291,6 +2420,7 @@ static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
constraint_target_to_mat4(ct->tar, constraint_target_to_mat4(ct->tar,
ct->subtarget, ct->subtarget,
ct->matrix, ct->matrix,
cob,
CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_WORLD,
ct->space, ct->space,
con->flag, con->flag,
@@ -2651,6 +2781,7 @@ static void actcon_get_tarmat(struct Depsgraph *depsgraph,
constraint_target_to_mat4(ct->tar, constraint_target_to_mat4(ct->tar,
ct->subtarget, ct->subtarget,
tempmat, tempmat,
cob,
CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_WORLD,
ct->space, ct->space,
con->flag, con->flag,
@@ -4112,7 +4243,7 @@ static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
* See T42447. */ * See T42447. */
unit_m4(mat); unit_m4(mat);
BKE_constraint_mat_convertspace( BKE_constraint_mat_convertspace(
cob->ob, cob->pchan, mat, CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace, true); cob->ob, cob->pchan, mat, cob, CONSTRAINT_SPACE_LOCAL, scon->projAxisSpace, true);
invert_m4(mat); invert_m4(mat);
mul_mat3_m4_v3(mat, no); mul_mat3_m4_v3(mat, no);
@@ -6044,7 +6175,7 @@ void BKE_constraints_solve(struct Depsgraph *depsgraph,
/* move owner matrix into right space */ /* move owner matrix into right space */
BKE_constraint_mat_convertspace( BKE_constraint_mat_convertspace(
cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace, false); cob->ob, cob->pchan, cob->matrix, cob, CONSTRAINT_SPACE_WORLD, con->ownspace, false);
/* prepare targets for constraint solving */ /* prepare targets for constraint solving */
BKE_constraint_targets_for_solving_get(depsgraph, con, cob, &targets, ctime); BKE_constraint_targets_for_solving_get(depsgraph, con, cob, &targets, ctime);
@@ -6063,7 +6194,7 @@ void BKE_constraints_solve(struct Depsgraph *depsgraph,
/* move owner back into world-space for next constraint/other business */ /* move owner back into world-space for next constraint/other business */
if ((con->flag & CONSTRAINT_SPACEONCE) == 0) { if ((con->flag & CONSTRAINT_SPACEONCE) == 0) {
BKE_constraint_mat_convertspace( BKE_constraint_mat_convertspace(
cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD, false); cob->ob, cob->pchan, cob->matrix, cob, con->ownspace, CONSTRAINT_SPACE_WORLD, false);
} }
/* Interpolate the enforcement, to blend result of constraint into final owner transform /* Interpolate the enforcement, to blend result of constraint into final owner transform

View File

@@ -411,7 +411,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
/* Extract transform just like how the constraints do it! */ /* Extract transform just like how the constraints do it! */
copy_m4_m4(mat, pchan->pose_mat); copy_m4_m4(mat, pchan->pose_mat);
BKE_constraint_mat_convertspace( BKE_constraint_mat_convertspace(
ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false); ob, pchan, mat, NULL, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
/* ... and from that, we get our transform. */ /* ... and from that, we get our transform. */
copy_v3_v3(tmp_loc, mat[3]); copy_v3_v3(tmp_loc, mat[3]);
@@ -437,7 +437,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
/* Extract transform just like how the constraints do it! */ /* Extract transform just like how the constraints do it! */
copy_m4_m4(mat, ob->obmat); copy_m4_m4(mat, ob->obmat);
BKE_constraint_mat_convertspace( BKE_constraint_mat_convertspace(
ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); ob, NULL, mat, NULL, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
/* ... and from that, we get our transform. */ /* ... and from that, we get our transform. */
copy_v3_v3(tmp_loc, mat[3]); copy_v3_v3(tmp_loc, mat[3]);
@@ -514,7 +514,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
/* Just like how the constraints do it! */ /* Just like how the constraints do it! */
copy_m4_m4(mat, pchan->pose_mat); copy_m4_m4(mat, pchan->pose_mat);
BKE_constraint_mat_convertspace( BKE_constraint_mat_convertspace(
ob, pchan, mat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false); ob, pchan, mat, NULL, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL, false);
} }
else { else {
/* Specially calculate local matrix, since chan_mat is not valid /* Specially calculate local matrix, since chan_mat is not valid
@@ -541,7 +541,7 @@ static float dvar_eval_transChan(ChannelDriver *driver, DriverVar *dvar)
/* Just like how the constraints do it! */ /* Just like how the constraints do it! */
copy_m4_m4(mat, ob->obmat); copy_m4_m4(mat, ob->obmat);
BKE_constraint_mat_convertspace( BKE_constraint_mat_convertspace(
ob, NULL, mat, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false); ob, NULL, mat, NULL, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, false);
} }
else { else {
/* Transforms to matrix. */ /* Transforms to matrix. */

View File

@@ -326,6 +326,17 @@ static void do_versions_291_fcurve_handles_limit(FCurve *fcu)
} }
} }
static void do_version_constraints_copy_transforms_split_mode(ListBase *lb)
{
LISTBASE_FOREACH (bConstraint *, con, lb) {
if (con->type == CONSTRAINT_TYPE_TRANSLIKE) {
bTransLikeConstraint *data = (bTransLikeConstraint *)con->data;
data->split_mode = (data->mix_mode == TRANSLIKE_MIX_REPLACE) ? TRANSLIKE_SPLIT_NONE :
TRANSLIKE_SPLIT_SCALE;
}
}
}
void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
{ {
UNUSED_VARS(fd); UNUSED_VARS(fd);
@@ -759,5 +770,17 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
mesh->symmetry = mesh->editflag & (ME_SYMMETRY_X | ME_SYMMETRY_Y | ME_SYMMETRY_Z); mesh->symmetry = mesh->editflag & (ME_SYMMETRY_X | ME_SYMMETRY_Y | ME_SYMMETRY_Z);
} }
} }
/* Split mode in Copy Transforms constraint. */
if (!DNA_struct_elem_find(fd->filesdna, "bTransLikeConstraint", "char", "split_mode")) {
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
do_version_constraints_copy_transforms_split_mode(&ob->constraints);
if (ob->pose) {
LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
do_version_constraints_copy_transforms_split_mode(&pchan->constraints);
}
}
}
}
} }
} }

View File

@@ -442,20 +442,19 @@ static void updateDuplicateSubtarget(EditBone *dup_bone,
} }
} }
static void updateDuplicateActionConstraintSettings(EditBone *dup_bone, static void updateDuplicateActionConstraintSettings(
EditBone *orig_bone, EditBone *dup_bone, EditBone *orig_bone, Object *ob, bPoseChannel *pchan, bConstraint *curcon)
Object *ob,
bConstraint *curcon)
{ {
bActionConstraint *act_con = (bActionConstraint *)curcon->data; bActionConstraint *act_con = (bActionConstraint *)curcon->data;
bAction *act = (bAction *)act_con->act; bAction *act = (bAction *)act_con->act;
bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = pchan};
float mat[4][4]; float mat[4][4];
unit_m4(mat); unit_m4(mat);
bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, act_con->subtarget); bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, act_con->subtarget);
BKE_constraint_mat_convertspace( BKE_constraint_mat_convertspace(
ob, target_pchan, mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false); ob, target_pchan, mat, &cob, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false);
float max_axis_val = 0; float max_axis_val = 0;
int max_axis = 0; int max_axis = 0;
@@ -592,6 +591,8 @@ static void updateDuplicateLocRotConstraintSettings(Object *ob,
bRotLimitConstraint *limit = (bRotLimitConstraint *)curcon->data; bRotLimitConstraint *limit = (bRotLimitConstraint *)curcon->data;
float local_mat[4][4], imat[4][4]; float local_mat[4][4], imat[4][4];
bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = pchan};
float min_vec[3], max_vec[3]; float min_vec[3], max_vec[3];
min_vec[0] = limit->xmin; min_vec[0] = limit->xmin;
@@ -605,7 +606,7 @@ static void updateDuplicateLocRotConstraintSettings(Object *ob,
unit_m4(local_mat); unit_m4(local_mat);
BKE_constraint_mat_convertspace( BKE_constraint_mat_convertspace(
ob, pchan, local_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false); ob, pchan, local_mat, &cob, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false);
if (curcon->type == CONSTRAINT_TYPE_ROTLIMIT) { if (curcon->type == CONSTRAINT_TYPE_ROTLIMIT) {
/* Zero out any location translation */ /* Zero out any location translation */
@@ -656,9 +657,11 @@ static void updateDuplicateTransformConstraintSettings(Object *ob,
float target_mat[4][4], own_mat[4][4], imat[4][4]; float target_mat[4][4], own_mat[4][4], imat[4][4];
bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = pchan};
unit_m4(own_mat); unit_m4(own_mat);
BKE_constraint_mat_convertspace( BKE_constraint_mat_convertspace(
ob, pchan, own_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false); ob, pchan, own_mat, &cob, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false);
/* ###Source map mirroring### */ /* ###Source map mirroring### */
float old_min, old_max; float old_min, old_max;
@@ -716,7 +719,7 @@ static void updateDuplicateTransformConstraintSettings(Object *ob,
bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, trans->subtarget); bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, trans->subtarget);
unit_m4(target_mat); unit_m4(target_mat);
BKE_constraint_mat_convertspace( BKE_constraint_mat_convertspace(
ob, target_pchan, target_mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false); ob, target_pchan, target_mat, &cob, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false);
invert_m4_m4(imat, target_mat); invert_m4_m4(imat, target_mat);
/* convert values into local object space */ /* convert values into local object space */
@@ -826,7 +829,7 @@ static void updateDuplicateConstraintSettings(EditBone *dup_bone, EditBone *orig
for (curcon = conlist->first; curcon; curcon = curcon->next) { for (curcon = conlist->first; curcon; curcon = curcon->next) {
switch (curcon->type) { switch (curcon->type) {
case CONSTRAINT_TYPE_ACTION: case CONSTRAINT_TYPE_ACTION:
updateDuplicateActionConstraintSettings(dup_bone, orig_bone, ob, curcon); updateDuplicateActionConstraintSettings(dup_bone, orig_bone, ob, pchan, curcon);
break; break;
case CONSTRAINT_TYPE_KINEMATIC: case CONSTRAINT_TYPE_KINEMATIC:
updateDuplicateKinematicConstraintSettings(curcon); updateDuplicateKinematicConstraintSettings(curcon);

View File

@@ -307,8 +307,10 @@ typedef struct bSameVolumeConstraint {
/* Copy Transform Constraint */ /* Copy Transform Constraint */
typedef struct bTransLikeConstraint { typedef struct bTransLikeConstraint {
struct Object *tar; struct Object *tar;
int flag;
char mix_mode; char mix_mode;
char _pad[7]; char split_mode;
char _pad[2];
/** MAX_ID_NAME-2. */ /** MAX_ID_NAME-2. */
char subtarget[64]; char subtarget[64];
} bTransLikeConstraint; } bTransLikeConstraint;
@@ -725,6 +727,10 @@ typedef enum eBConstraint_SpaceTypes {
CONSTRAINT_SPACE_POSE = 2, CONSTRAINT_SPACE_POSE = 2,
/** For posechannels - local with parent. */ /** For posechannels - local with parent. */
CONSTRAINT_SPACE_PARLOCAL = 3, CONSTRAINT_SPACE_PARLOCAL = 3,
/** For posechannels - local converted to the pose orientation. */
CONSTRAINT_SPACE_ABSLOCAL = 6,
/** For posechannels - local converted to the owner bone orientation. */
CONSTRAINT_SPACE_OWNLOCAL = 7,
/** For files from between 2.43-2.46 (should have been parlocal). */ /** For files from between 2.43-2.46 (should have been parlocal). */
CONSTRAINT_SPACE_INVALID = 4, /* do not exchange for anything! */ CONSTRAINT_SPACE_INVALID = 4, /* do not exchange for anything! */
} eBConstraint_SpaceTypes; } eBConstraint_SpaceTypes;
@@ -795,6 +801,12 @@ typedef enum eCopyScale_Flags {
SIZELIKE_UNIFORM = (1 << 5), SIZELIKE_UNIFORM = (1 << 5),
} eCopyScale_Flags; } eCopyScale_Flags;
/* bTransLikeConstraint.flag */
typedef enum eCopyTransforms_Flags {
/* Invert the transformation matrix. */
TRANSLIKE_INVERT = (1 << 0),
} eCopyTransforms_Flags;
/* bTransLikeConstraint.mix_mode */ /* bTransLikeConstraint.mix_mode */
typedef enum eCopyTransforms_MixMode { typedef enum eCopyTransforms_MixMode {
/* Replace rotation channel values. */ /* Replace rotation channel values. */
@@ -805,6 +817,16 @@ typedef enum eCopyTransforms_MixMode {
TRANSLIKE_MIX_AFTER = 2, TRANSLIKE_MIX_AFTER = 2,
} eCopyTransforms_MixMode; } eCopyTransforms_MixMode;
/* bTransLikeConstraint.split_mode */
typedef enum eCopyTransforms_SplitMode {
/* Replace rotation channel values. */
TRANSLIKE_SPLIT_SCALE = 0,
/* Handle as separate location, rotation and scale. */
TRANSLIKE_SPLIT_ALL = 1,
/* Handle as a single matrix. */
TRANSLIKE_SPLIT_NONE = 2,
} eCopyTransforms_SplitMode;
/* bTransformConstraint.to/from */ /* bTransformConstraint.to/from */
typedef enum eTransform_ToFrom { typedef enum eTransform_ToFrom {
TRANS_LOCATION = 0, TRANS_LOCATION = 0,

View File

@@ -218,6 +218,18 @@ static const EnumPropertyItem target_space_pchan_items[] = {
"Local Space", "Local Space",
"The transformation of the target is evaluated relative to its local " "The transformation of the target is evaluated relative to its local "
"coordinate system"}, "coordinate system"},
{CONSTRAINT_SPACE_ABSLOCAL,
"ABSOLUTE_LOCAL",
0,
"Absolute Local Space",
"The local transformation of the target bone is evaluated relative to its local "
"coordinate system, as if the bone had zero world space rotation in its rest pose"},
{CONSTRAINT_SPACE_OWNLOCAL,
"OWNER_LOCAL",
0,
"Owner Local Space",
"The local transformation of the target bone is evaluated relative to its local coordinate "
"system, as if the target and owner bones had the same orientation in their rest pose"},
{0, NULL, 0, NULL, NULL}, {0, NULL, 0, NULL, NULL},
}; };
@@ -243,6 +255,12 @@ static const EnumPropertyItem owner_space_pchan_items[] = {
0, 0,
"Local Space", "Local Space",
"The constraint is applied relative to the local coordinate system of the object"}, "The constraint is applied relative to the local coordinate system of the object"},
{CONSTRAINT_SPACE_ABSLOCAL,
"ABSOLUTE_LOCAL",
0,
"Absolute Local Space",
"The constraint is applied relative to the local coordinate system of the bone, "
"as if the owner bone had zero world space rotation in its rest pose"},
{0, NULL, 0, NULL, NULL}, {0, NULL, 0, NULL, NULL},
}; };
@@ -1599,14 +1617,32 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
"BEFORE", "BEFORE",
0, 0,
"Before Original", "Before Original",
"Apply copied transformation before original, as if the constraint target is a parent. " "Apply copied transformation before original, as if the constraint target is a parent."},
"Scale is handled specially to avoid creating shear"},
{TRANSLIKE_MIX_AFTER, {TRANSLIKE_MIX_AFTER,
"AFTER", "AFTER",
0, 0,
"After Original", "After Original",
"Apply copied transformation after original, as if the constraint target is a child. " "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},
};
static const EnumPropertyItem split_mode_items[] = {
{TRANSLIKE_SPLIT_SCALE,
"SCALE",
0,
"Split Scale",
"Handle scale specially to avoid creating shear"},
{TRANSLIKE_SPLIT_ALL,
"ALL",
0,
"Split All",
"Separately process location, rotation and scale, similar to a sequence "
"of three separate Copy constraints"},
{TRANSLIKE_SPLIT_NONE,
"NONE",
0,
"No Split (Allows Shear)",
"Treat the transformation as a single unit, using simple matrix math"},
{0, NULL, 0, NULL, NULL}, {0, NULL, 0, NULL, NULL},
}; };
@@ -1624,6 +1660,11 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
RNA_define_lib_overridable(true); RNA_define_lib_overridable(true);
prop = RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", TRANSLIKE_INVERT);
RNA_def_property_ui_text(prop, "Invert", "Invert the copied transformation");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE); prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mix_mode"); RNA_def_property_enum_sdna(prop, NULL, "mix_mode");
RNA_def_property_enum_items(prop, mix_mode_items); RNA_def_property_enum_items(prop, mix_mode_items);
@@ -1631,6 +1672,13 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
prop, "Mix Mode", "Specify how the copied and existing transformations are combined"); prop, "Mix Mode", "Specify how the copied and existing transformations are combined");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "split_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "split_mode");
RNA_def_property_enum_items(prop, split_mode_items);
RNA_def_property_ui_text(
prop, "Split Mode", "Specify how the location, rotation and scale components are handled");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
RNA_define_lib_overridable(false); RNA_define_lib_overridable(false);
} }

View File

@@ -58,6 +58,11 @@ static const EnumPropertyItem space_items[] = {
"Local With Parent", "Local With Parent",
"The rest pose local space of a bone (thus matrix includes parent transforms)"}, "The rest pose local space of a bone (thus matrix includes parent transforms)"},
{CONSTRAINT_SPACE_LOCAL, "LOCAL", 0, "Local Space", "The local space of an object/bone"}, {CONSTRAINT_SPACE_LOCAL, "LOCAL", 0, "Local Space", "The local space of an object/bone"},
{CONSTRAINT_SPACE_ABSLOCAL,
"ABSOLUTE_LOCAL",
0,
"Absolute Local Space",
"The local space of an object/bone, as if it had zero world space rotation in rest pose"},
{0, NULL, 0, NULL, NULL}, {0, NULL, 0, NULL, NULL},
}; };
@@ -305,7 +310,7 @@ static void rna_Object_mat_convert_space(Object *ob,
/* Error in case of invalid from/to values when pchan is NULL */ /* Error in case of invalid from/to values when pchan is NULL */
if (pchan == NULL) { if (pchan == NULL) {
if (ELEM(from, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_PARLOCAL)) { if (ELEM(from, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_PARLOCAL, CONSTRAINT_SPACE_ABSLOCAL)) {
const char *identifier = NULL; const char *identifier = NULL;
RNA_enum_identifier(space_items, from, &identifier); RNA_enum_identifier(space_items, from, &identifier);
BKE_reportf(reports, BKE_reportf(reports,
@@ -314,7 +319,7 @@ static void rna_Object_mat_convert_space(Object *ob,
identifier); identifier);
return; return;
} }
if (ELEM(to, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_PARLOCAL)) { if (ELEM(to, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_PARLOCAL, CONSTRAINT_SPACE_ABSLOCAL)) {
const char *identifier = NULL; const char *identifier = NULL;
RNA_enum_identifier(space_items, to, &identifier); RNA_enum_identifier(space_items, to, &identifier);
BKE_reportf(reports, BKE_reportf(reports,
@@ -325,7 +330,7 @@ static void rna_Object_mat_convert_space(Object *ob,
} }
} }
BKE_constraint_mat_convertspace(ob, pchan, (float(*)[4])mat_ret, from, to, false); BKE_constraint_mat_convertspace(ob, pchan, (float(*)[4])mat_ret, NULL, from, to, false);
} }
static void rna_Object_calc_matrix_camera(Object *ob, static void rna_Object_calc_matrix_camera(Object *ob,