1
1

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)
layout.prop(con, "invert")
layout.prop(con, "split_mode", text="Components")
layout.prop(con, "mix_mode", text="Mix")
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,
struct bPoseChannel *pchan,
float mat[4][4],
bConstraintOb *cob,
short from,
short to,
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.
* For now, this is only implemented for Objects and PoseChannels.
*/
void BKE_constraint_mat_convertspace(
Object *ob, bPoseChannel *pchan, float mat[4][4], short from, short to, const bool keep_scale)
void BKE_constraint_mat_convertspace(Object *ob,
bPoseChannel *pchan,
float mat[4][4],
bConstraintOb *cob,
short from,
short to,
const bool keep_scale)
{
float diff_mat[4][4];
float imat[4][4];
@@ -281,9 +286,10 @@ void BKE_constraint_mat_convertspace(
mul_m4_m4m4(mat, imat, mat);
/* 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 */
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;
}
@@ -294,9 +300,25 @@ void BKE_constraint_mat_convertspace(
mul_m4_m4m4(mat, ob->obmat, mat);
}
/* 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) {
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 */
@@ -309,17 +331,32 @@ void BKE_constraint_mat_convertspace(
break;
}
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 */
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) */
BKE_armature_mat_bone_to_pose(pchan, mat, mat);
}
/* 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 */
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;
}
@@ -331,9 +368,10 @@ void BKE_constraint_mat_convertspace(
}
/* 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 */
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;
}
@@ -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,
const char *substring,
float mat[4][4],
bConstraintOb *cob,
short from,
short to,
short flag,
@@ -576,7 +615,7 @@ static void constraint_target_to_mat4(Object *ob,
/* Case OBJECT */
if (substring[0] == '\0') {
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 */
/* 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) {
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) {
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 */
else {
@@ -656,7 +695,7 @@ static void constraint_target_to_mat4(Object *ob,
}
/* 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),
bConstraint *con,
bConstraintOb *UNUSED(cob),
bConstraintOb *cob,
bConstraintTarget *ct,
float UNUSED(ctime))
{
@@ -707,6 +746,7 @@ static void default_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
constraint_target_to_mat4(ct->tar,
ct->subtarget,
ct->matrix,
cob,
CONSTRAINT_SPACE_WORLD,
ct->space,
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),
bConstraint *con,
bConstraintOb *UNUSED(cob),
bConstraintOb *cob,
bConstraintTarget *ct,
float UNUSED(ctime))
{
@@ -729,6 +769,7 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph),
constraint_target_to_mat4(ct->tar,
ct->subtarget,
ct->matrix,
cob,
CONSTRAINT_SPACE_WORLD,
ct->space,
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,
ct->subtarget,
ct->matrix,
cob,
CONSTRAINT_SPACE_WORLD,
ct->space,
con->flag,
@@ -2106,21 +2148,108 @@ static void translike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
bConstraintTarget *ct = targets->first;
if (VALID_CONS_TARGET(ct)) {
switch (data->mix_mode) {
case TRANSLIKE_MIX_REPLACE:
copy_m4_m4(cob->matrix, ct->matrix);
break;
float mat[4][4], scale[3];
copy_m4_m4(mat, ct->matrix);
case TRANSLIKE_MIX_BEFORE:
mul_m4_m4m4_aligned_scale(cob->matrix, ct->matrix, cob->matrix);
break;
switch (data->split_mode) {
case TRANSLIKE_SPLIT_NONE: {
if (data->flag & TRANSLIKE_INVERT) {
invert_m4(mat);
}
case TRANSLIKE_MIX_AFTER:
mul_m4_m4m4_aligned_scale(cob->matrix, cob->matrix, ct->matrix);
switch (data->mix_mode) {
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;
}
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:
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) */
static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
bConstraint *con,
bConstraintOb *UNUSED(cob),
bConstraintOb *cob,
bConstraintTarget *ct,
float UNUSED(ctime))
{
@@ -2291,6 +2420,7 @@ static void pycon_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
constraint_target_to_mat4(ct->tar,
ct->subtarget,
ct->matrix,
cob,
CONSTRAINT_SPACE_WORLD,
ct->space,
con->flag,
@@ -2651,6 +2781,7 @@ static void actcon_get_tarmat(struct Depsgraph *depsgraph,
constraint_target_to_mat4(ct->tar,
ct->subtarget,
tempmat,
cob,
CONSTRAINT_SPACE_WORLD,
ct->space,
con->flag,
@@ -4112,7 +4243,7 @@ static void shrinkwrap_get_tarmat(struct Depsgraph *UNUSED(depsgraph),
* See T42447. */
unit_m4(mat);
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);
mul_mat3_m4_v3(mat, no);
@@ -6044,7 +6175,7 @@ void BKE_constraints_solve(struct Depsgraph *depsgraph,
/* move owner matrix into right space */
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 */
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 */
if ((con->flag & CONSTRAINT_SPACEONCE) == 0) {
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

View File

@@ -411,7 +411,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar)
/* Extract transform just like how the constraints do it! */
copy_m4_m4(mat, pchan->pose_mat);
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. */
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! */
copy_m4_m4(mat, ob->obmat);
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. */
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! */
copy_m4_m4(mat, pchan->pose_mat);
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 {
/* 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! */
copy_m4_m4(mat, ob->obmat);
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 {
/* 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)
{
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);
}
}
/* 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,
EditBone *orig_bone,
Object *ob,
bConstraint *curcon)
static void updateDuplicateActionConstraintSettings(
EditBone *dup_bone, EditBone *orig_bone, Object *ob, bPoseChannel *pchan, bConstraint *curcon)
{
bActionConstraint *act_con = (bActionConstraint *)curcon->data;
bAction *act = (bAction *)act_con->act;
bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = pchan};
float mat[4][4];
unit_m4(mat);
bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, act_con->subtarget);
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;
int max_axis = 0;
@@ -592,6 +591,8 @@ static void updateDuplicateLocRotConstraintSettings(Object *ob,
bRotLimitConstraint *limit = (bRotLimitConstraint *)curcon->data;
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];
min_vec[0] = limit->xmin;
@@ -605,7 +606,7 @@ static void updateDuplicateLocRotConstraintSettings(Object *ob,
unit_m4(local_mat);
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) {
/* 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];
bConstraintOb cob = {.depsgraph = NULL, .scene = NULL, .ob = ob, .pchan = pchan};
unit_m4(own_mat);
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### */
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);
unit_m4(target_mat);
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);
/* 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) {
switch (curcon->type) {
case CONSTRAINT_TYPE_ACTION:
updateDuplicateActionConstraintSettings(dup_bone, orig_bone, ob, curcon);
updateDuplicateActionConstraintSettings(dup_bone, orig_bone, ob, pchan, curcon);
break;
case CONSTRAINT_TYPE_KINEMATIC:
updateDuplicateKinematicConstraintSettings(curcon);

View File

@@ -307,8 +307,10 @@ typedef struct bSameVolumeConstraint {
/* Copy Transform Constraint */
typedef struct bTransLikeConstraint {
struct Object *tar;
int flag;
char mix_mode;
char _pad[7];
char split_mode;
char _pad[2];
/** MAX_ID_NAME-2. */
char subtarget[64];
} bTransLikeConstraint;
@@ -725,6 +727,10 @@ typedef enum eBConstraint_SpaceTypes {
CONSTRAINT_SPACE_POSE = 2,
/** For posechannels - local with parent. */
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). */
CONSTRAINT_SPACE_INVALID = 4, /* do not exchange for anything! */
} eBConstraint_SpaceTypes;
@@ -795,6 +801,12 @@ typedef enum eCopyScale_Flags {
SIZELIKE_UNIFORM = (1 << 5),
} eCopyScale_Flags;
/* bTransLikeConstraint.flag */
typedef enum eCopyTransforms_Flags {
/* Invert the transformation matrix. */
TRANSLIKE_INVERT = (1 << 0),
} eCopyTransforms_Flags;
/* bTransLikeConstraint.mix_mode */
typedef enum eCopyTransforms_MixMode {
/* Replace rotation channel values. */
@@ -805,6 +817,16 @@ typedef enum eCopyTransforms_MixMode {
TRANSLIKE_MIX_AFTER = 2,
} 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 */
typedef enum eTransform_ToFrom {
TRANS_LOCATION = 0,

View File

@@ -218,6 +218,18 @@ static const EnumPropertyItem target_space_pchan_items[] = {
"Local Space",
"The transformation of the target is evaluated relative to its local "
"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},
};
@@ -243,6 +255,12 @@ static const EnumPropertyItem owner_space_pchan_items[] = {
0,
"Local Space",
"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},
};
@@ -1599,14 +1617,32 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
"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"},
"Apply copied transformation before original, as if the constraint target is a parent."},
{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"},
"Apply copied transformation after original, as if the constraint target is a child."},
{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},
};
@@ -1624,6 +1660,11 @@ static void rna_def_constraint_transform_like(BlenderRNA *brna)
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);
RNA_def_property_enum_sdna(prop, NULL, "mix_mode");
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");
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);
}

View File

@@ -58,6 +58,11 @@ static const EnumPropertyItem space_items[] = {
"Local With Parent",
"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_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},
};
@@ -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 */
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;
RNA_enum_identifier(space_items, from, &identifier);
BKE_reportf(reports,
@@ -314,7 +319,7 @@ static void rna_Object_mat_convert_space(Object *ob,
identifier);
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;
RNA_enum_identifier(space_items, to, &identifier);
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,