diff options
author | Sebastian Parborg <darkdefende@gmail.com> | 2020-04-10 14:58:56 +0300 |
---|---|---|
committer | Sebastian Parborg <darkdefende@gmail.com> | 2020-04-10 15:01:02 +0300 |
commit | 9a7f5f1bb42292eeb70b4832e7883846df0cb76a (patch) | |
tree | 039d9017f2815b4689ecd051ee39a7323d79bbc2 /source | |
parent | 9c5b0542069bfec5ba8bfa65fa031014d3750cbe (diff) |
Fix T67232: Multiples targetless IKs in a chain gives weird behaviour (known as FakeIK for FK posing)
The issue was that the deps graph relation builder assumed that all
bones that had a IK constraint on them would be evaluated. However for
targetless IK bones, only the active bone would receive updates and the
others would be skipped (as those would be treated as if the IK
constraint was disabled).
I didn't see an easy way to solve this from the depsgraph side of
things.
Instead I came up with a solution that I feel is quite strait forward
and reflects what is actually supposed to happen under the hood.
Now all targetless IK constraints are treated as disabled and will not
be added to any relations in the depsgraph.
Instead, a temporary IK constraint will be created when the bone in
question is transformed. This is basically activating "Auto IK" for the
bone while transforming.
Reviewed By: Sergey, Brecht
Differential Revision: http://developer.blender.org/D7378
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc | 6 | ||||
-rw-r--r-- | source/blender/editors/transform/transform_convert_armature.c | 66 |
2 files changed, 52 insertions, 20 deletions
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index 6fe9a3c2a00..d05385a7d7c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -68,6 +68,12 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object, bConstraint *con, RootPChanMap *root_map) { + if ((con->flag & CONSTRAINT_DISABLE) != 0) { + /* Do not add disabled IK constraints to the relations. If these needs to be temporarly + * enabled, they will be added as temporary constraints during transform. */ + return; + } + bKinematicConstraint *data = (bKinematicConstraint *)con->data; /* Attach owner to IK Solver to. */ bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index e52bd15b0d5..481198ea88c 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -58,6 +58,34 @@ typedef struct BoneInitData { float zwidth; } BoneInitData; +static void add_temporary_ik_constraint(bPoseChannel *pchan, bKinematicConstraint *targetless_con) +{ + bConstraint *con = BKE_constraint_add_for_pose( + NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC); + + /* for draw, but also for detecting while pose solving */ + pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET); + + bKinematicConstraint *temp_con_data = con->data; + + if (targetless_con) { + /* if exists, use values from last targetless (but disabled) IK-constraint as base */ + *temp_con_data = *targetless_con; + } + else { + temp_con_data->flag = CONSTRAINT_IK_TIP; + } + + temp_con_data->flag |= CONSTRAINT_IK_TEMP | CONSTRAINT_IK_AUTO | CONSTRAINT_IK_POS; +} + +static void update_deg_with_temporary_ik(Main *bmain, Object *ob) +{ + BIK_clear_data(ob->pose); + /* TODO(sergey): Consider doing partial update only. */ + DEG_relations_tag_update(bmain); +} + static void add_pose_transdata( TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td) { @@ -200,8 +228,16 @@ static void add_pose_transdata( } td->loc = data->grabtarget; copy_v3_v3(td->iloc, td->loc); + data->flag |= CONSTRAINT_IK_AUTO; + /* Add a temporary auto IK constraint here, as we will only temporarly active this targetless + * bone during transform. (Targetless IK constraints are treated as if they are disabled + * unless they are transformed) */ + add_temporary_ik_constraint(pchan, data); + Main *bmain = CTX_data_main(t->context); + update_deg_with_temporary_ik(bmain, ob); + /* only object matrix correction */ copy_m3_m3(td->mtx, omat); pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON); @@ -221,7 +257,8 @@ bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan) bConstraint *con = pchan->constraints.first; for (; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) { + if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->flag & CONSTRAINT_OFF) == 0 && + (con->enforce != 0.0f)) { bKinematicConstraint *data = con->data; if (data->tar == NULL) { @@ -278,8 +315,6 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan) } } } - - return 0; } } @@ -289,20 +324,7 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan) } } - con = BKE_constraint_add_for_pose(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC); - - /* for draw, but also for detecting while pose solving */ - pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET); - - data = con->data; - if (targetless) { - /* if exists, use values from last targetless (but disabled) IK-constraint as base */ - *data = *targetless; - } - else { - data->flag = CONSTRAINT_IK_TIP; - } - data->flag |= CONSTRAINT_IK_TEMP | CONSTRAINT_IK_AUTO | CONSTRAINT_IK_POS; + add_temporary_ik_constraint(pchan, targetless); copy_v3_v3(data->grabtarget, pchan->pose_tail); /* watch-it! has to be 0 here, since we're still on the @@ -415,9 +437,7 @@ static short pose_grab_with_ik(Main *bmain, Object *ob) /* iTaSC needs clear for new IK constraints */ if (tot_ik) { - BIK_clear_data(ob->pose); - /* TODO(sergey): Consider doing partial update only. */ - DEG_relations_tag_update(bmain); + update_deg_with_temporary_ik(bmain, ob); } return (tot_ik) ? 1 : 0; @@ -585,6 +605,12 @@ void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, Object * /* TODO(germano): Realitve Mirror support */ } data->flag |= CONSTRAINT_IK_AUTO; + /* Add a temporary auto IK constraint here, as we will only temporarly active this targetless + * bone during transform. (Targetless IK constraints are treated as if they are disabled + * unless they are transformed) */ + add_temporary_ik_constraint(pchan, data); + Main *bmain = CTX_data_main(t->context); + update_deg_with_temporary_ik(bmain, ob); } if (pid) { |