diff options
Diffstat (limited to 'source/blender/blenkernel/intern/constraint.c')
-rw-r--r-- | source/blender/blenkernel/intern/constraint.c | 238 |
1 files changed, 196 insertions, 42 deletions
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index e1e4d138fd9..d59849695ff 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -62,6 +62,7 @@ #include "BKE_deform.h" #include "BKE_displist.h" #include "BKE_editmesh.h" +#include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_library.h" @@ -1801,25 +1802,47 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar bConstraintTarget *ct = targets->first; if (VALID_CONS_TARGET(ct)) { - float loc[3]; - float eul[3], obeul[3]; - float size[3]; + float loc[3], size[3], oldrot[3][3], newrot[3][3]; + float eul[3], obeul[3], defeul[3]; - copy_v3_v3(loc, cob->matrix[3]); - mat4_to_size(size, cob->matrix); + mat4_to_loc_rot_size(loc, oldrot, size, cob->matrix); + + /* Select the Euler rotation order, defaulting to the owner. */ + short rot_order = cob->rotOrder; + + if (data->euler_order != CONSTRAINT_EULER_AUTO) { + rot_order = data->euler_order; + } /* To allow compatible rotations, must get both rotations in the order of the owner... */ - mat4_to_eulO(obeul, cob->rotOrder, cob->matrix); + mat4_to_eulO(obeul, rot_order, cob->matrix); /* We must get compatible eulers from the beginning because * some of them can be modified below (see bug T21875). */ - mat4_to_compatible_eulO(eul, obeul, cob->rotOrder, ct->matrix); + mat4_to_compatible_eulO(eul, obeul, rot_order, ct->matrix); + + /* Prepare the copied euler rotation. */ + bool legacy_offset = false; + + switch (data->mix_mode) { + case ROTLIKE_MIX_OFFSET: + legacy_offset = true; + copy_v3_v3(defeul, obeul); + break; + + case ROTLIKE_MIX_REPLACE: + copy_v3_v3(defeul, obeul); + break; + + default: + zero_v3(defeul); + } if ((data->flag & ROTLIKE_X) == 0) { - eul[0] = obeul[0]; + eul[0] = defeul[0]; } else { - if (data->flag & ROTLIKE_OFFSET) { - rotate_eulO(eul, cob->rotOrder, 'X', obeul[0]); + if (legacy_offset) { + rotate_eulO(eul, rot_order, 'X', obeul[0]); } if (data->flag & ROTLIKE_X_INVERT) { @@ -1828,11 +1851,11 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar } if ((data->flag & ROTLIKE_Y) == 0) { - eul[1] = obeul[1]; + eul[1] = defeul[1]; } else { - if (data->flag & ROTLIKE_OFFSET) { - rotate_eulO(eul, cob->rotOrder, 'Y', obeul[1]); + if (legacy_offset) { + rotate_eulO(eul, rot_order, 'Y', obeul[1]); } if (data->flag & ROTLIKE_Y_INVERT) { @@ -1841,11 +1864,11 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar } if ((data->flag & ROTLIKE_Z) == 0) { - eul[2] = obeul[2]; + eul[2] = defeul[2]; } else { - if (data->flag & ROTLIKE_OFFSET) { - rotate_eulO(eul, cob->rotOrder, 'Z', obeul[2]); + if (legacy_offset) { + rotate_eulO(eul, rot_order, 'Z', obeul[2]); } if (data->flag & ROTLIKE_Z_INVERT) { @@ -1853,10 +1876,36 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar } } + /* Add the euler components together if needed. */ + if (data->mix_mode == ROTLIKE_MIX_ADD) { + add_v3_v3(eul, obeul); + } + /* Good to make eulers compatible again, * since we don't know how much they were changed above. */ compatible_eul(eul, obeul); - loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder); + eulO_to_mat3(newrot, eul, rot_order); + + /* Mix the rotation matrices: */ + switch (data->mix_mode) { + case ROTLIKE_MIX_REPLACE: + case ROTLIKE_MIX_OFFSET: + case ROTLIKE_MIX_ADD: + break; + + case ROTLIKE_MIX_BEFORE: + mul_m3_m3m3(newrot, newrot, oldrot); + break; + + case ROTLIKE_MIX_AFTER: + mul_m3_m3m3(newrot, oldrot, newrot); + break; + + default: + BLI_assert(false); + } + + loc_rot_size_to_mat4(cob->matrix, loc, newrot, size); } } @@ -1927,9 +1976,39 @@ static void sizelike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *ta if (VALID_CONS_TARGET(ct)) { float obsize[3], size[3]; - mat4_to_size(size, ct->matrix); mat4_to_size(obsize, cob->matrix); + /* Compute one uniform scale factor to apply to all three axes. */ + if (data->flag & SIZELIKE_UNIFORM) { + const int all_axes = SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z; + float total = 1.0f; + + /* If all axes are selected, use the determinant. */ + if ((data->flag & all_axes) == all_axes) { + total = fabsf(mat4_to_volume_scale(ct->matrix)); + } + /* Otherwise multiply individual values. */ + else { + mat4_to_size(size, ct->matrix); + + if (data->flag & SIZELIKE_X) { + total *= size[0]; + } + if (data->flag & SIZELIKE_Y) { + total *= size[1]; + } + if (data->flag & SIZELIKE_Z) { + total *= size[2]; + } + } + + copy_v3_fl(size, cbrt(total)); + } + /* Regular per-axis scaling. */ + else { + mat4_to_size(size, ct->matrix); + } + for (int i = 0; i < 3; i++) { size[i] = powf(size[i], data->power); } @@ -1948,13 +2027,13 @@ static void sizelike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *ta } } - if ((data->flag & SIZELIKE_X) && (obsize[0] != 0)) { + if ((data->flag & (SIZELIKE_X | SIZELIKE_UNIFORM)) && (obsize[0] != 0)) { mul_v3_fl(cob->matrix[0], size[0] / obsize[0]); } - if ((data->flag & SIZELIKE_Y) && (obsize[1] != 0)) { + if ((data->flag & (SIZELIKE_Y | SIZELIKE_UNIFORM)) && (obsize[1] != 0)) { mul_v3_fl(cob->matrix[1], size[1] / obsize[1]); } - if ((data->flag & SIZELIKE_Z) && (obsize[2] != 0)) { + if ((data->flag & (SIZELIKE_Z | SIZELIKE_UNIFORM)) && (obsize[2] != 0)) { mul_v3_fl(cob->matrix[2], size[2] / obsize[2]); } } @@ -2011,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); + } } } @@ -2301,9 +2410,9 @@ static void armdef_get_tarmat(struct Depsgraph *UNUSED(depsgraph), } static void armdef_accumulate_matrix(float obmat[4][4], - float iobmat[4][4], - float basemat[4][4], - float bonemat[4][4], + const float iobmat[4][4], + const float basemat[4][4], + const float bonemat[4][4], float weight, float r_sum_mat[4][4], DualQuat *r_sum_dq) @@ -3644,6 +3753,11 @@ static void transform_new_data(void *cdata) data->map[0] = 0; data->map[1] = 1; data->map[2] = 2; + + for (int i = 0; i < 3; i++) { + data->from_min_scale[i] = data->from_max_scale[i] = 1.0f; + data->to_min_scale[i] = data->to_max_scale[i] = 1.0f; + } } static void transform_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata) @@ -3688,8 +3802,10 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t /* only evaluate if there is a target */ if (VALID_CONS_TARGET(ct)) { float *from_min, *from_max, *to_min, *to_max; - float loc[3], eul[3], size[3]; - float dvec[3], sval[3]; + float loc[3], rot[3][3], oldeul[3], size[3]; + float newloc[3], newrot[3][3], neweul[3], newsize[3]; + float dbuf[4], sval[3]; + float *const dvec = dbuf + 1; int i; /* obtain target effect */ @@ -3708,7 +3824,8 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t from_max = data->from_max_scale; break; case TRANS_ROTATION: - mat4_to_eulO(dvec, cob->rotOrder, ct->matrix); + BKE_driver_target_matrix_to_rot_channels( + ct->matrix, cob->rotOrder, data->from_rotation_mode, -1, true, dbuf); from_min = data->from_min_rot; from_max = data->from_max_rot; break; @@ -3720,10 +3837,15 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t break; } + /* Select the output Euler rotation order, defaulting to the owner. */ + short rot_order = cob->rotOrder; + + if (data->to == TRANS_ROTATION && data->to_euler_order != CONSTRAINT_EULER_AUTO) { + rot_order = data->to_euler_order; + } + /* extract components of owner's matrix */ - copy_v3_v3(loc, cob->matrix[3]); - mat4_to_eulO(eul, cob->rotOrder, cob->matrix); - mat4_to_size(size, cob->matrix); + mat4_to_loc_rot_size(loc, rot, size, cob->matrix); /* determine where in range current transforms lie */ if (data->expo) { @@ -3755,18 +3877,42 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t to_min = data->to_min_scale; to_max = data->to_max_scale; for (i = 0; i < 3; i++) { - /* multiply with original scale (so that it can still be scaled) */ - /* size[i] *= to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); */ - /* Stay absolute, else it breaks existing rigs... sigh. */ - size[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); + newsize[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); + } + switch (data->mix_mode_scale) { + case TRANS_MIXSCALE_MULTIPLY: + mul_v3_v3(size, newsize); + break; + case TRANS_MIXSCALE_REPLACE: + default: + copy_v3_v3(size, newsize); + break; } break; case TRANS_ROTATION: to_min = data->to_min_rot; to_max = data->to_max_rot; for (i = 0; i < 3; i++) { - /* add to original rotation (so that it can still be rotated) */ - eul[i] += to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); + neweul[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); + } + switch (data->mix_mode_rot) { + case TRANS_MIXROT_REPLACE: + eulO_to_mat3(rot, neweul, rot_order); + break; + case TRANS_MIXROT_BEFORE: + eulO_to_mat3(newrot, neweul, rot_order); + mul_m3_m3m3(rot, newrot, rot); + break; + case TRANS_MIXROT_AFTER: + eulO_to_mat3(newrot, neweul, rot_order); + mul_m3_m3m3(rot, rot, newrot); + break; + case TRANS_MIXROT_ADD: + default: + mat3_to_eulO(oldeul, rot_order, rot); + add_v3_v3(neweul, oldeul); + eulO_to_mat3(rot, neweul, rot_order); + break; } break; case TRANS_LOCATION: @@ -3774,14 +3920,22 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t to_min = data->to_min; to_max = data->to_max; for (i = 0; i < 3; i++) { - /* add to original location (so that it can still be moved) */ - loc[i] += (to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]))); + newloc[i] = (to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]))); + } + switch (data->mix_mode_loc) { + case TRANS_MIXLOC_REPLACE: + copy_v3_v3(loc, newloc); + break; + case TRANS_MIXLOC_ADD: + default: + add_v3_v3(loc, newloc); + break; } break; } /* apply to matrix */ - loc_eulO_size_to_mat4(cob->matrix, loc, eul, size, cob->rotOrder); + loc_rot_size_to_mat4(cob->matrix, loc, rot, size); } } |