[Bf-blender-cvs] [10162d68e38] master: Constraints: replace 'Set Inverse' operator with an eval-time update

Sybren A. Stüvel noreply at git.blender.org
Thu Feb 27 10:38:11 CET 2020


Commit: 10162d68e38514aa8741cf9efd9e0f5deac32085
Author: Sybren A. Stüvel
Date:   Thu Feb 27 10:24:11 2020 +0100
Branches: master
https://developer.blender.org/rB10162d68e38514aa8741cf9efd9e0f5deac32085

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

===================================================================

M	source/blender/blenkernel/intern/constraint.c
M	source/blender/editors/object/object_constraint.c
M	source/blender/makesdna/DNA_constraint_types.h
M	source/blender/makesrna/intern/rna_constraint.c
M	tests/python/bl_constraints.py

===================================================================

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 = {
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 906a9e44870..bfff36bb83a 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -871,118 +871,31 @@ void CONSTRAINT_OT_limitdistance_reset(wmOperatorType *ot)
 
 /* ------------- Child-Of Constraint ------------------ */
 
-static void child_get_inverse_matrix_owner_bone(
-    Depsgraph *depsgraph, wmOperator *op, Scene *scene, Object *ob, float invmat[4][4])
+/* Force evaluation so that the 'set inverse' flag is handled.
+ * No-op when the constraint is enabled, as in such cases the evaluation will happen anyway.
+ */
+static void force_evaluation_if_constraint_disabled(bContext *C, Object *ob, bConstraint *con)
 {
-  /* For bone owner we want to do this in evaluated domain.
-   * BKE_pose_where_is / BKE_pose_where_is_bone relies on (re)evaluating parts of the scene
-   * and copying new evaluated stuff back to original.
-   */
-  Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
-  bConstraint *con_eval = edit_constraint_property_get(op, ob_eval, CONSTRAINT_TYPE_CHILDOF);
-
-  /* nullify inverse matrix first */
-  unit_m4(invmat);
-
-  bPoseChannel *pchan_eval = BKE_pose_channel_active(ob_eval);
-
-  /* try to find a pose channel - assume that this is the constraint owner */
-  /* TODO: get from context instead? */
-  if (ob_eval && ob_eval->pose && pchan_eval) {
-    bConstraint *con_last;
-
-    /* calculate/set inverse matrix:
-     * We just calculate all transform-stack eval up to but not including this constraint.
-     * This is because inverse should just inverse correct for just the constraint's influence
-     * when it gets applied; that is, at the time of application, we don't know anything about
-     * what follows.
-     */
-    float imat[4][4], tmat[4][4];
-    float pmat[4][4];
-
-    /* make sure we passed the correct constraint */
-    BLI_assert(BLI_findindex(&pchan_eval->constraints, con_eval) != -1);
-
-    /* 1. calculate posemat where inverse doesn't exist yet (inverse was cleared above),
-     * to use as baseline ("pmat") to derive delta from. This extra calc saves users
-     * from having pressing "Clear Inverse" first
-     */
-    BKE_pose_where_is(depsgraph, scene, ob_eval);
-    copy_m4_m4(pmat, pchan_eval->pose_mat);
-
-    /* 2. knock out constraints starting from this one */
-    con_last = pchan_eval->constraints.last;
-    pchan_eval->constraints.last = con_eval->prev;
-
-    if (con_eval->prev) {
-      /* new end must not point to this one, else this chain cutting is useless */
-      con_eval->prev->next = NULL;
-    }
-    else {
-      /* constraint was first */
-      pchan_eval->constraints.first = NULL;
-    }
-
-    /* 3. solve pose without disabled constraints */
-    BKE_pose_where_is(depsgraph, scene, ob_eval);
-
-    /* 4. determine effect of constraint by removing the newly calculated
-     * pchan->pose_mat from the original pchan->pose_mat, thus determining
-     * the effect of the constraint
-     */
-    invert_m4_m4(imat, pchan_eval->pose_mat);
-    mul_m4_m4m4(tmat, pmat, imat);
-    invert_m4_m4(invmat, tmat);
-
-    /* 5. restore constraints */
-    pchan_eval->constraints.last = con_last;
-
-    if (con_eval->prev) {
-      /* hook up prev to this one again */
-      con_eval->prev->next = con_eval;
-    }
-    else {
-      /* set as first again */
-      pchan_eval->constraints.first = con_eval;
-    }
-
-    /* 6. recalculate pose with new inv-mat applied */
-    /* this one is unnecessary? (DEG seems to update correctl

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list