Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/transform/transform_convert_armature.c
| Show First 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | typedef struct BoneInitData { | ||||
| float rad_tail; | float rad_tail; | ||||
| float roll; | float roll; | ||||
| float head[3]; | float head[3]; | ||||
| float dist; | float dist; | ||||
| float xwidth; | float xwidth; | ||||
| float zwidth; | float zwidth; | ||||
| } BoneInitData; | } 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( | static void add_pose_transdata( | ||||
| TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td) | TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td) | ||||
| { | { | ||||
| Bone *bone = pchan->bone; | Bone *bone = pchan->bone; | ||||
| float pmat[3][3], omat[3][3]; | float pmat[3][3], omat[3][3]; | ||||
| float cmat[3][3], tmat[3][3]; | float cmat[3][3], tmat[3][3]; | ||||
| float vec[3]; | float vec[3]; | ||||
| ▲ Show 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | if (data) { | ||||
| if (data->flag & CONSTRAINT_IK_TIP) { | if (data->flag & CONSTRAINT_IK_TIP) { | ||||
| copy_v3_v3(data->grabtarget, pchan->pose_tail); | copy_v3_v3(data->grabtarget, pchan->pose_tail); | ||||
| } | } | ||||
| else { | else { | ||||
| copy_v3_v3(data->grabtarget, pchan->pose_head); | copy_v3_v3(data->grabtarget, pchan->pose_head); | ||||
| } | } | ||||
| td->loc = data->grabtarget; | td->loc = data->grabtarget; | ||||
| copy_v3_v3(td->iloc, td->loc); | copy_v3_v3(td->iloc, td->loc); | ||||
| data->flag |= CONSTRAINT_IK_AUTO; | 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 */ | /* only object matrix correction */ | ||||
| copy_m3_m3(td->mtx, omat); | copy_m3_m3(td->mtx, omat); | ||||
| pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON); | pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON); | ||||
| } | } | ||||
| } | } | ||||
| /* store reference to first constraint */ | /* store reference to first constraint */ | ||||
| td->con = pchan->constraints.first; | td->con = pchan->constraints.first; | ||||
| } | } | ||||
brecht: Is this code also needed in `pose_transform_mirror_update` which also sets `CONSTRAINT_IK_AUTO`? | |||||
Done Inline ActionsFor the deg tagging, I guess that I could modify the functions to keep track if they added temporary ik constraints. I don't know how much this will help in practice though as I suspect that only one targetless (or two if in mirror mode) would be active at the same time for most use cases. Do you want me to add extra logic for this? zeddb: For the deg tagging, I guess that I could modify the functions to keep track if they added… | |||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Pose Auto-IK | /** \name Pose Auto-IK | ||||
| * \{ */ | * \{ */ | ||||
| bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan) | bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan) | ||||
| { | { | ||||
| bConstraint *con = pchan->constraints.first; | bConstraint *con = pchan->constraints.first; | ||||
| for (; con; con = con->next) { | 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; | bKinematicConstraint *data = con->data; | ||||
| if (data->tar == NULL) { | if (data->tar == NULL) { | ||||
| return data; | return data; | ||||
| } | } | ||||
| if (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0) { | if (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0) { | ||||
| return data; | return data; | ||||
| } | } | ||||
| Show All 40 Lines | if (con->type == CONSTRAINT_TYPE_KINEMATIC) { | ||||
| if (pchan->protectflag & OB_LOCK_ROTY) { | if (pchan->protectflag & OB_LOCK_ROTY) { | ||||
| pchan->ikflag |= BONE_IK_NO_YDOF_TEMP; | pchan->ikflag |= BONE_IK_NO_YDOF_TEMP; | ||||
| } | } | ||||
| if (pchan->protectflag & OB_LOCK_ROTZ) { | if (pchan->protectflag & OB_LOCK_ROTZ) { | ||||
| pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP; | pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return 0; | |||||
| } | } | ||||
| } | } | ||||
| if ((con->flag & CONSTRAINT_DISABLE) == 0 && (con->enforce != 0.0f)) { | if ((con->flag & CONSTRAINT_DISABLE) == 0 && (con->enforce != 0.0f)) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| con = BKE_constraint_add_for_pose(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC); | add_temporary_ik_constraint(pchan, targetless); | ||||
| /* 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; | |||||
| copy_v3_v3(data->grabtarget, pchan->pose_tail); | copy_v3_v3(data->grabtarget, pchan->pose_tail); | ||||
| /* watch-it! has to be 0 here, since we're still on the | /* watch-it! has to be 0 here, since we're still on the | ||||
| * same bone for the first time through the loop T25885. */ | * same bone for the first time through the loop T25885. */ | ||||
| data->rootbone = 0; | data->rootbone = 0; | ||||
| /* we only include bones that are part of a continual connected chain */ | /* we only include bones that are part of a continual connected chain */ | ||||
| do { | do { | ||||
| ▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | if (pchan->bone->layer & arm->layer) { | ||||
| tot_ik += pose_grab_with_ik_children(ob->pose, pchan->bone); | tot_ik += pose_grab_with_ik_children(ob->pose, pchan->bone); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* iTaSC needs clear for new IK constraints */ | /* iTaSC needs clear for new IK constraints */ | ||||
| if (tot_ik) { | if (tot_ik) { | ||||
| BIK_clear_data(ob->pose); | update_deg_with_temporary_ik(bmain, ob); | ||||
| /* TODO(sergey): Consider doing partial update only. */ | |||||
| DEG_relations_tag_update(bmain); | |||||
| } | } | ||||
| return (tot_ik) ? 1 : 0; | return (tot_ik) ? 1 : 0; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| ▲ Show 20 Lines • Show All 151 Lines • ▼ Show 20 Lines | if (t->mode == TFM_TRANSLATION) { | ||||
| if (data == NULL) { | if (data == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| mul_v3_m4v3(data->grabtarget, flip_mtx, td->loc); | mul_v3_m4v3(data->grabtarget, flip_mtx, td->loc); | ||||
| if (pid) { | if (pid) { | ||||
| /* TODO(germano): Realitve Mirror support */ | /* TODO(germano): Realitve Mirror support */ | ||||
| } | } | ||||
| data->flag |= CONSTRAINT_IK_AUTO; | 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) { | if (pid) { | ||||
| pid++; | pid++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 469 Lines • Show Last 20 Lines | |||||
Is this code also needed in pose_transform_mirror_update which also sets CONSTRAINT_IK_AUTO?
Can this code be deduplicated with similar code in pose_grab_with_ik_add?
Can we call BIK_clear_data and DEG_relations_tag_update only once, after the constraints have been added for all bones?