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:
-rw-r--r--source/blender/blenkernel/intern/constraint.c128
-rw-r--r--source/blender/editors/object/object_constraint.c136
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h4
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c13
-rw-r--r--tests/python/bl_constraints.py35
5 files changed, 135 insertions, 181 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 = {
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 correctly without)
- + if we leave this in, we have to click "Set Inverse" twice to see updates...
- BKE_pose_where_is(depsgraph, scene, ob_eval); */
+ if ((con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) == 0) {
+ return;
}
-}
-
-static void child_get_inverse_matrix_owner_object(
- Depsgraph *depsgraph, Scene *scene, Object *ob, bConstraint *con, float invmat[4][4])
-{
- /* nullify inverse matrix first */
- unit_m4(invmat);
-
- if (ob) {
- Object workob;
-
- /* make sure we passed the correct constraint */
- BLI_assert(BLI_findindex(&ob->constraints, con) != -1);
- UNUSED_VARS_NDEBUG(con);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = DEG_get_evaluated_scene(depsgraph);
- /* use BKE_object_workob_calc_parent to find inverse - just like for normal parenting */
- BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob);
- invert_m4_m4(invmat, workob.obmat);
- }
+ short flag_backup = con->flag;
+ con->flag &= ~(CONSTRAINT_DISABLE | CONSTRAINT_OFF);
+ BKE_object_eval_constraints(depsgraph, scene, ob);
+ con->flag = flag_backup;
}
/* ChildOf Constraint - set inverse callback */
static int childof_set_inverse_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_CHILDOF);
bChildOfConstraint *data = (con) ? (bChildOfConstraint *)con->data : NULL;
- const int owner = RNA_enum_get(op->ptr, "owner");
/* despite 3 layers of checks, we may still not be able to find a constraint */
if (data == NULL) {
@@ -991,12 +904,11 @@ static int childof_set_inverse_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) {
- child_get_inverse_matrix_owner_object(depsgraph, scene, ob, con, data->invmat);
- }
- else if (owner == EDIT_CONSTRAINT_OWNER_BONE) {
- child_get_inverse_matrix_owner_bone(depsgraph, op, scene, ob, data->invmat);
- }
+ /* Set a flag to request recalculation on next update. */
+ data->flag |= CHILDOF_SET_INVERSE;
+
+ /* Force constraint to run, it will perform the recalculation. */
+ force_evaluation_if_constraint_disabled(C, ob, con);
ED_object_constraint_update(bmain, ob);
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
@@ -1231,12 +1143,9 @@ void CONSTRAINT_OT_followpath_path_animate(wmOperatorType *ot)
static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_OBJECTSOLVER);
bObjectSolverConstraint *data = (con) ? (bObjectSolverConstraint *)con->data : NULL;
- const int owner = RNA_enum_get(op->ptr, "owner");
/* despite 3 layers of checks, we may still not be able to find a constraint */
if (data == NULL) {
@@ -1246,12 +1155,11 @@ static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) {
- child_get_inverse_matrix_owner_object(depsgraph, scene, ob, con, data->invmat);
- }
- else if (owner == EDIT_CONSTRAINT_OWNER_BONE) {
- child_get_inverse_matrix_owner_bone(depsgraph, op, scene, ob, data->invmat);
- }
+ /* Set a flag to request recalculation on next update. */
+ data->flag |= OBJECTSOLVER_SET_INVERSE;
+
+ /* Force constraint to run, it will perform the recalculation. */
+ force_evaluation_if_constraint_disabled(C, ob, con);
ED_object_constraint_update(bmain, ob);
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 6caa0ac5a74..670a6c46187 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -1096,6 +1096,8 @@ typedef enum eChildOf_Flags {
CHILDOF_SIZEY = (1 << 7),
CHILDOF_SIZEZ = (1 << 8),
CHILDOF_ALL = 511,
+ /* Temporary flag used by the Set Inverse operator. */
+ CHILDOF_SET_INVERSE = (1 << 9),
} eChildOf_Flags;
/* Pivot Constraint */
@@ -1147,6 +1149,8 @@ typedef enum eCameraSolver_Flags {
/* ObjectSolver Constraint -> flag */
typedef enum eObjectSolver_Flags {
OBJECTSOLVER_ACTIVECLIP = (1 << 0),
+ /* Temporary flag used by the Set Inverse operator. */
+ OBJECTSOLVER_SET_INVERSE = (1 << 1),
} eObjectSolver_Flags;
/* ObjectSolver Constraint -> flag */
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 8e57de9baeb..64e6fc9059c 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -973,11 +973,18 @@ static void rna_def_constraint_childof(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Scale Z", "Use Z Scale of Parent");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ prop = RNA_def_property(srna, "set_inverse_pending", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CHILDOF_SET_INVERSE);
+ RNA_def_property_ui_text(
+ prop, "Set Inverse Pending", "Set to true to request recalculation of the inverse matrix");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
prop = RNA_def_property(srna, "inverse_matrix", PROP_FLOAT, PROP_MATRIX);
RNA_def_property_float_sdna(prop, NULL, "invmat");
RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Inverse Matrix", "Transformation matrix to apply before");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
}
static void rna_def_constraint_python(BlenderRNA *brna)
@@ -3152,6 +3159,12 @@ static void rna_def_constraint_object_solver(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Active Clip", "Use active clip defined in scene");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+ prop = RNA_def_property(srna, "set_inverse_pending", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", OBJECTSOLVER_SET_INVERSE);
+ RNA_def_property_ui_text(
+ prop, "Set Inverse Pending", "Set to true to request recalculation of the inverse matrix");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
/* object */
prop = RNA_def_property(srna, "object", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "object");
diff --git a/tests/python/bl_constraints.py b/tests/python/bl_constraints.py
index 42f81bddce6..13a431541bc 100644
--- a/tests/python/bl_constraints.py
+++ b/tests/python/bl_constraints.py
@@ -156,9 +156,9 @@ class ChildOfTest(AbstractConstraintTests):
context = self.constraint_context('Child Of', owner_name='Child Of.object.owner')
bpy.ops.constraint.childof_set_inverse(context, constraint='Child Of')
self.matrix_test('Child Of.object.owner', Matrix((
- (0.9228900671005249, 0.23250490427017212, -0.035540513694286346, 0.10000000149011612),
- (-0.011224273592233658, 0.9838480949401855, 0.24731633067131042, 0.21246682107448578),
- (0.0383986234664917, -0.3163823187351227, 0.9553266167640686, 0.27248233556747437),
+ (0.9992386102676392, 0.019843991845846176, -0.03359176218509674, 0.10000000149011612),
+ (-0.017441775649785995, 0.997369647026062, 0.0703534483909607, 0.2000001221895218),
+ (0.034899499267339706, -0.06971398741006851, 0.996956467628479, 0.3000001311302185),
(0.0, 0.0, 0.0, 1.0),
)))
@@ -188,6 +188,29 @@ class ChildOfTest(AbstractConstraintTests):
bpy.ops.constraint.childof_clear_inverse(context, constraint='Child Of')
self.matrix_test('Child Of.armature.owner', initial_matrix)
+ def test_vertexgroup_simple_parent(self):
+ """Child Of: simple evaluation of vertex group parent."""
+ initial_matrix = Matrix((
+ (-0.8076590895652771, 0.397272527217865, 0.4357309341430664, 1.188504934310913),
+ (-0.4534659683704376, -0.8908230066299438, -0.028334975242614746, 1.7851561307907104),
+ (0.3769024908542633, -0.22047416865825653, 0.8996308445930481, 3.4457669258117676),
+ (0.0, 0.0, 0.0, 1.0),
+ ))
+ self.matrix_test('Child Of.vertexgroup.owner', initial_matrix)
+
+ context = self.constraint_context('Child Of', owner_name='Child Of.vertexgroup.owner')
+ bpy.ops.constraint.childof_set_inverse(context, constraint='Child Of')
+
+ self.matrix_test('Child Of.vertexgroup.owner', Matrix((
+ (0.9992386102676392, 0.019843988120555878, -0.03359176218509674, 0.10000000149011612),
+ (-0.017441775649785995, 0.997369647026062, 0.0703534483909607, 0.20000000298023224),
+ (0.03489949554204941, -0.06971397995948792, 0.9969563484191895, 0.30000001192092896),
+ (0.0, 0.0, 0.0, 1.0),
+ )))
+
+ bpy.ops.constraint.childof_clear_inverse(context, constraint='Child Of')
+ self.matrix_test('Child Of.vertexgroup.owner', initial_matrix)
+
class ObjectSolverTest(AbstractConstraintTests):
layer_collection = 'Object Solver'
@@ -205,9 +228,9 @@ class ObjectSolverTest(AbstractConstraintTests):
context = self.constraint_context('Object Solver')
bpy.ops.constraint.objectsolver_set_inverse(context, constraint='Object Solver')
self.matrix_test('Object Solver.owner', Matrix((
- (0.9992386102676392, 0.019843988120555878, -0.03359176218509674, 0.10000000149011612),
- (-0.017441775649785995, 0.997369647026062, 0.0703534483909607, 0.20000000298023224),
- (0.03489949554204941, -0.06971397995948792, 0.9969563484191895, 0.30000001192092896),
+ (0.9992387294769287, 0.019843989983201027, -0.03359176591038704, 0.10000025480985641),
+ (-0.017441747710108757, 0.9973697662353516, 0.07035345584154129, 0.1999993920326233),
+ (0.034899502992630005, -0.06971398741006851, 0.996956467628479, 0.29999980330467224),
(0.0, 0.0, 0.0, 1.0),
)))