fix [#34203] Editing bones, parenting, blender quits
'Set Inverse' was mixing up pose/object constraints
This commit is contained in:
@@ -718,81 +718,87 @@ void CONSTRAINT_OT_limitdistance_reset(wmOperatorType *ot)
|
|||||||
|
|
||||||
/* ------------- Child-Of Constraint ------------------ */
|
/* ------------- Child-Of Constraint ------------------ */
|
||||||
|
|
||||||
static void child_get_inverse_matrix(Scene *scene, Object *ob, bConstraint *con, float invmat[4][4])
|
static void child_get_inverse_matrix(Scene *scene, Object *ob, bConstraint *con, float invmat[4][4], const int owner)
|
||||||
{
|
{
|
||||||
bConstraint *lastcon = NULL;
|
|
||||||
bPoseChannel *pchan = NULL;
|
|
||||||
|
|
||||||
/* nullify inverse matrix first */
|
/* nullify inverse matrix first */
|
||||||
unit_m4(invmat);
|
unit_m4(invmat);
|
||||||
|
|
||||||
/* try to find a pose channel - assume that this is the constraint owner */
|
if (owner == EDIT_CONSTRAINT_OWNER_BONE) {
|
||||||
/* TODO: get from context instead? */
|
bPoseChannel *pchan;
|
||||||
if (ob && ob->pose)
|
/* try to find a pose channel - assume that this is the constraint owner */
|
||||||
pchan = BKE_pose_channel_active(ob);
|
/* TODO: get from context instead? */
|
||||||
|
if (ob && ob->pose && (pchan = BKE_pose_channel_active(ob))) {
|
||||||
|
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];
|
||||||
|
|
||||||
/* calculate/set inverse matrix:
|
/* make sure we passed the correct constraint */
|
||||||
* We just calculate all transform-stack eval up to but not including this constraint.
|
BLI_assert(BLI_findindex(&pchan->constraints, con) != -1);
|
||||||
* 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 imat[4][4], tmat[4][4];
|
|
||||||
float pmat[4][4];
|
|
||||||
|
|
||||||
/* 1. calculate posemat where inverse doesn't exist yet (inverse was cleared above),
|
/* 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
|
* to use as baseline ("pmat") to derive delta from. This extra calc saves users
|
||||||
* from having pressing "Clear Inverse" first
|
* from having pressing "Clear Inverse" first
|
||||||
*/
|
*/
|
||||||
BKE_pose_where_is(scene, ob);
|
BKE_pose_where_is(scene, ob);
|
||||||
copy_m4_m4(pmat, pchan->pose_mat);
|
copy_m4_m4(pmat, pchan->pose_mat);
|
||||||
|
|
||||||
/* 2. knock out constraints starting from this one */
|
/* 2. knock out constraints starting from this one */
|
||||||
lastcon = pchan->constraints.last;
|
con_last = pchan->constraints.last;
|
||||||
pchan->constraints.last = con->prev;
|
pchan->constraints.last = con->prev;
|
||||||
|
|
||||||
if (con->prev) {
|
if (con->prev) {
|
||||||
/* new end must not point to this one, else this chain cutting is useless */
|
/* new end must not point to this one, else this chain cutting is useless */
|
||||||
con->prev->next = NULL;
|
con->prev->next = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* constraint was first */
|
||||||
|
pchan->constraints.first = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. solve pose without disabled constraints */
|
||||||
|
BKE_pose_where_is(scene, ob);
|
||||||
|
|
||||||
|
/* 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->pose_mat);
|
||||||
|
mult_m4_m4m4(tmat, pmat, imat);
|
||||||
|
invert_m4_m4(invmat, tmat);
|
||||||
|
|
||||||
|
/* 5. restore constraints */
|
||||||
|
pchan->constraints.last = con_last;
|
||||||
|
|
||||||
|
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 */
|
||||||
|
BKE_pose_where_is(scene, ob);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
/* constraint was first */
|
|
||||||
pchan->constraints.first = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 3. solve pose without disabled constraints */
|
|
||||||
BKE_pose_where_is(scene, ob);
|
|
||||||
|
|
||||||
/* 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->pose_mat);
|
|
||||||
mult_m4_m4m4(tmat, pmat, imat);
|
|
||||||
invert_m4_m4(invmat, tmat);
|
|
||||||
|
|
||||||
/* 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 */
|
|
||||||
BKE_pose_where_is(scene, ob);
|
|
||||||
}
|
}
|
||||||
else if (ob) {
|
if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) {
|
||||||
Object workob;
|
if (ob) {
|
||||||
|
Object workob;
|
||||||
|
|
||||||
/* use BKE_object_workob_calc_parent to find inverse - just like for normal parenting */
|
/* make sure we passed the correct constraint */
|
||||||
BKE_object_workob_calc_parent(scene, ob, &workob);
|
BLI_assert(BLI_findindex(&ob->constraints, con) != -1);
|
||||||
invert_m4_m4(invmat, workob.obmat);
|
|
||||||
|
/* use BKE_object_workob_calc_parent to find inverse - just like for normal parenting */
|
||||||
|
BKE_object_workob_calc_parent(scene, ob, &workob);
|
||||||
|
invert_m4_m4(invmat, workob.obmat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -803,6 +809,7 @@ static int childof_set_inverse_exec(bContext *C, wmOperator *op)
|
|||||||
Object *ob = ED_object_active_context(C);
|
Object *ob = ED_object_active_context(C);
|
||||||
bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_CHILDOF);
|
bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_CHILDOF);
|
||||||
bChildOfConstraint *data = (con) ? (bChildOfConstraint *)con->data : NULL;
|
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 */
|
/* despite 3 layers of checks, we may still not be able to find a constraint */
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
@@ -811,7 +818,7 @@ static int childof_set_inverse_exec(bContext *C, wmOperator *op)
|
|||||||
return OPERATOR_CANCELLED;
|
return OPERATOR_CANCELLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
child_get_inverse_matrix(scene, ob, con, data->invmat);
|
child_get_inverse_matrix(scene, ob, con, data->invmat, owner);
|
||||||
|
|
||||||
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
|
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
|
||||||
|
|
||||||
@@ -1024,6 +1031,7 @@ static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op)
|
|||||||
Object *ob = ED_object_active_context(C);
|
Object *ob = ED_object_active_context(C);
|
||||||
bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_OBJECTSOLVER);
|
bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_OBJECTSOLVER);
|
||||||
bObjectSolverConstraint *data = (con) ? (bObjectSolverConstraint *)con->data : NULL;
|
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 */
|
/* despite 3 layers of checks, we may still not be able to find a constraint */
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
@@ -1032,7 +1040,7 @@ static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op)
|
|||||||
return OPERATOR_CANCELLED;
|
return OPERATOR_CANCELLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
child_get_inverse_matrix(scene, ob, con, data->invmat);
|
child_get_inverse_matrix(scene, ob, con, data->invmat, owner);
|
||||||
|
|
||||||
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
|
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user