Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSybren A. Stüvel <sybren@blender.org>2020-02-27 12:24:11 +0300
committerSybren A. Stüvel <sybren@blender.org>2020-02-27 12:37:59 +0300
commit10162d68e38514aa8741cf9efd9e0f5deac32085 (patch)
treed78cfe4761c1fef9ef7af434eed0551158c6ff55 /source/blender/blenkernel/intern/constraint.c
parent4952fb1669fb7d254fc26a527b6dc2a44ac2c496 (diff)
Constraints: replace 'Set Inverse' operator with an eval-time update
This fixes {T70269}. Before this commit there was complicated code to try and compute the correct parent inverse matrix for the 'Child Of' and 'Object Solver' constraints outside the constraint evaluation. This was done mostly correctly, but did have some issues. The Set Inverse operator now defers this computation to be performed during constraint evaluation by just setting a flag. If the constraint is disabled, and thus tagging it for update in the depsgraph is not enough to trigger immediate evaluation, evaluation is forced by temporarily enabling it. This fix changes the way how the inverse matrix works when some of the channels of the constraint are disabled. Before this commit, the channel flags were used to filter both the parent and the inverse matrix. This meant that it was impossible to make an inverse matrix that would actually fully neutralize the effect of the constraint. Now only the parent matrix is filtered, while inverse is applied fully. As a result, pressing the 'Set Inverse' matrix produces the same transformation as disabling the constraint. This is also reflected in the changed values in the 'Child Of' unit test. This change is not backward compatible, but it should be OK because the old way was effectively unusable, so it is unlikely anybody relied on it. The change in matrix for the Object Solver constraint is due to a different method of computing it, which caused a slightly different floating point error that was slightly bigger than allowed by the test, so I updated the matrix values there as well. This patch was original written by @angavrilov and subsequently updated by me. Differential Revision: https://developer.blender.org/D6091
Diffstat (limited to 'source/blender/blenkernel/intern/constraint.c')
-rw-r--r--source/blender/blenkernel/intern/constraint.c128
1 files changed, 67 insertions, 61 deletions
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 8ba746e3493..26dea11624b 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -860,94 +860,88 @@ static void childof_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
}
float parmat[4][4];
-
- /* simple matrix parenting */
- if (data->flag == CHILDOF_ALL) {
-
- /* multiply target (parent matrix) by offset (parent inverse) to get
- * the effect of the parent that will be exerted on the owner
- */
- mul_m4_m4m4(parmat, ct->matrix, data->invmat);
-
- /* now multiply the parent matrix by the owner matrix to get the
- * the effect of this constraint (i.e. owner is 'parented' to parent)
- */
- mul_m4_m4m4(cob->matrix, parmat, cob->matrix);
+ /* Simple matrix parenting. */
+ if ((data->flag & CHILDOF_ALL) == CHILDOF_ALL) {
+ copy_m4_m4(parmat, ct->matrix);
}
+ /* Filter the parent matrix by channel. */
else {
- float invmat[4][4], tempmat[4][4];
float loc[3], eul[3], size[3];
- float loco[3], eulo[3], sizo[3];
-
- /* get offset (parent-inverse) matrix */
- copy_m4_m4(invmat, data->invmat);
/* extract components of both matrices */
copy_v3_v3(loc, ct->matrix[3]);
mat4_to_eulO(eul, ct->rotOrder, ct->matrix);
mat4_to_size(size, ct->matrix);
- copy_v3_v3(loco, invmat[3]);
- mat4_to_eulO(eulo, cob->rotOrder, invmat);
- mat4_to_size(sizo, invmat);
-
/* disable channels not enabled */
if (!(data->flag & CHILDOF_LOCX)) {
- loc[0] = loco[0] = 0.0f;
+ loc[0] = 0.0f;
}
if (!(data->flag & CHILDOF_LOCY)) {
- loc[1] = loco[1] = 0.0f;
+ loc[1] = 0.0f;
}
if (!(data->flag & CHILDOF_LOCZ)) {
- loc[2] = loco[2] = 0.0f;
+ loc[2] = 0.0f;
}
if (!(data->flag & CHILDOF_ROTX)) {
- eul[0] = eulo[0] = 0.0f;
+ eul[0] = 0.0f;
}
if (!(data->flag & CHILDOF_ROTY)) {
- eul[1] = eulo[1] = 0.0f;
+ eul[1] = 0.0f;
}
if (!(data->flag & CHILDOF_ROTZ)) {
- eul[2] = eulo[2] = 0.0f;
+ eul[2] = 0.0f;
}
if (!(data->flag & CHILDOF_SIZEX)) {
- size[0] = sizo[0] = 1.0f;
+ size[0] = 1.0f;
}
if (!(data->flag & CHILDOF_SIZEY)) {
- size[1] = sizo[1] = 1.0f;
+ size[1] = 1.0f;
}
if (!(data->flag & CHILDOF_SIZEZ)) {
- size[2] = sizo[2] = 1.0f;
+ size[2] = 1.0f;
}
/* make new target mat and offset mat */
- loc_eulO_size_to_mat4(ct->matrix, loc, eul, size, ct->rotOrder);
- loc_eulO_size_to_mat4(invmat, loco, eulo, sizo, cob->rotOrder);
+ loc_eulO_size_to_mat4(parmat, loc, eul, size, ct->rotOrder);
+ }
- /* multiply target (parent matrix) by offset (parent inverse) to get
- * the effect of the parent that will be exerted on the owner
- */
- mul_m4_m4m4(parmat, ct->matrix, invmat);
+ /* Compute the inverse matrix if requested. */
+ if (data->flag & CHILDOF_SET_INVERSE) {
+ invert_m4_m4(data->invmat, parmat);
- /* now multiply the parent matrix by the owner matrix to get the
- * the effect of this constraint (i.e. owner is 'parented' to parent)
- */
- copy_m4_m4(tempmat, cob->matrix);
- mul_m4_m4m4(cob->matrix, parmat, tempmat);
+ data->flag &= ~CHILDOF_SET_INVERSE;
- /* without this, changes to scale and rotation can change location
- * of a parentless bone or a disconnected bone. Even though its set
- * to zero above. */
- if (!(data->flag & CHILDOF_LOCX)) {
- cob->matrix[3][0] = tempmat[3][0];
- }
- if (!(data->flag & CHILDOF_LOCY)) {
- cob->matrix[3][1] = tempmat[3][1];
- }
- if (!(data->flag & CHILDOF_LOCZ)) {
- cob->matrix[3][2] = tempmat[3][2];
+ /* Write the computed matrix back to the master copy if in COW evaluation. */
+ bConstraint *orig_con = constraint_find_original_for_update(cob, con);
+
+ if (orig_con != NULL) {
+ bChildOfConstraint *orig_data = orig_con->data;
+
+ copy_m4_m4(orig_data->invmat, data->invmat);
+ orig_data->flag &= ~CHILDOF_SET_INVERSE;
}
}
+
+ /* Multiply together the target (parent) matrix, parent inverse,
+ * and the owner transform matrixto get the effect of this constraint
+ * (i.e. owner is 'parented' to parent). */
+ float orig_cob_matrix[4][4];
+ copy_m4_m4(orig_cob_matrix, cob->matrix);
+ mul_m4_series(cob->matrix, parmat, data->invmat, orig_cob_matrix);
+
+ /* Without this, changes to scale and rotation can change location
+ * of a parentless bone or a disconnected bone. Even though its set
+ * to zero above. */
+ if (!(data->flag & CHILDOF_LOCX)) {
+ cob->matrix[3][0] = orig_cob_matrix[3][0];
+ }
+ if (!(data->flag & CHILDOF_LOCY)) {
+ cob->matrix[3][1] = orig_cob_matrix[3][1];
+ }
+ if (!(data->flag & CHILDOF_LOCZ)) {
+ cob->matrix[3][2] = orig_cob_matrix[3][2];
+ }
}
/* XXX note, con->flag should be CONSTRAINT_SPACEONCE for bone-childof, patched in readfile.c */
@@ -4891,23 +4885,35 @@ static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
return;
}
- float mat[4][4], obmat[4][4], imat[4][4], cammat[4][4], camimat[4][4], parmat[4][4];
+ float mat[4][4], obmat[4][4], imat[4][4], parmat[4][4];
float ctime = DEG_get_ctime(depsgraph);
float framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, ctime);
- BKE_object_where_is_calc_mat4(camob, cammat);
-
BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, framenr, mat);
- invert_m4_m4(camimat, cammat);
- mul_m4_m4m4(parmat, cammat, data->invmat);
+ invert_m4_m4(imat, mat);
+ mul_m4_m4m4(parmat, camob->obmat, imat);
- copy_m4_m4(cammat, camob->obmat);
copy_m4_m4(obmat, cob->matrix);
- invert_m4_m4(imat, mat);
+ /* Recalculate the inverse matrix if requested. */
+ if (data->flag & OBJECTSOLVER_SET_INVERSE) {
+ invert_m4_m4(data->invmat, parmat);
+
+ data->flag &= ~OBJECTSOLVER_SET_INVERSE;
+
+ /* Write the computed matrix back to the master copy if in COW evaluation. */
+ bConstraint *orig_con = constraint_find_original_for_update(cob, con);
+
+ if (orig_con != NULL) {
+ bObjectSolverConstraint *orig_data = orig_con->data;
+
+ copy_m4_m4(orig_data->invmat, data->invmat);
+ orig_data->flag &= ~OBJECTSOLVER_SET_INVERSE;
+ }
+ }
- mul_m4_series(cob->matrix, cammat, imat, camimat, parmat, obmat);
+ mul_m4_series(cob->matrix, parmat, data->invmat, obmat);
}
static bConstraintTypeInfo CTI_OBJECTSOLVER = {