diff options
-rw-r--r-- | source/blender/editors/object/object_constraint.c | 52 |
1 files changed, 41 insertions, 11 deletions
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 3c84b2df1d2..40d52e0b261 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -691,6 +691,7 @@ static int childof_set_inverse_exec (bContext *C, wmOperator *op) 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; + bConstraint *lastcon = NULL; bPoseChannel *pchan= NULL; /* despite 3 layers of checks, we may still not be able to find a constraint */ @@ -703,27 +704,45 @@ static int childof_set_inverse_exec (bContext *C, wmOperator *op) /* nullify inverse matrix first */ unit_m4(data->invmat); - /* try to find a pose channel */ + /* try to find a pose channel - assume that this is the constraint owner */ // TODO: get from context instead? if (ob && ob->pose) pchan= get_active_posechannel(ob); - /* calculate/set inverse matrix */ + /* 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. + */ if (pchan) { - float pmat[4][4], cinf; float imat[4][4], tmat[4][4]; + float pmat[4][4]; - /* make copy of pchan's original pose-mat (for use later) */ + /* 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 + */ + where_is_pose(scene, ob); copy_m4_m4(pmat, pchan->pose_mat); - /* disable constraint for pose to be solved without it */ - cinf= con->enforce; - con->enforce= 0.0f; + /* 2. knock out constraints starting from this one */ + lastcon = pchan->constraints.last; + pchan->constraints.last = con->prev; + + if (con->prev) { + /* new end must not point to this one, else this chain cutting is useless */ + con->prev->next = NULL; + } + else { + /* constraint was first */ + pchan->constraints.first = NULL; + } - /* solve pose without constraint */ + /* 3. solve pose without disabled constraints */ where_is_pose(scene, ob); - /* determine effect of constraint by removing the newly calculated + /* 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 */ @@ -731,8 +750,19 @@ static int childof_set_inverse_exec (bContext *C, wmOperator *op) mul_m4_m4m4(tmat, imat, pmat); invert_m4_m4(data->invmat, tmat); - /* recalculate pose with new inv-mat */ - con->enforce= cinf; + /* 5. restore constraints */ + pchan->constraints.last = lastcon; + + if (con->prev) { + /* hook up prev to this one again */ + con->prev->next = con; + } + else { + /* set as first again */ + pchan->constraints.first = con; + } + + /* 6. recalculate pose with new inv-mat applied */ where_is_pose(scene, ob); } else if (ob) { |