From de530a95dc7b482dc22c933b9b8b2a98c79b5663 Mon Sep 17 00:00:00 2001 From: mano-wii Date: Thu, 2 Jan 2020 12:48:30 -0300 Subject: Transform: Pose: Partial support for Auto IK + X-Mirror Fix T69572 TODO: support `Relative-Mirror` as well. Maniphest Tasks: T69572 Differential Revision: https://developer.blender.org/D5862 --- .../blender/editors/transform/transform_convert.c | 7 +- .../editors/transform/transform_convert_armature.c | 65 ++++++++-------- .../blender/editors/transform/transform_generics.c | 88 ++++++++++++---------- .../editors/transform/transform_orientations.c | 2 +- source/blender/makesrna/intern/rna_pose.c | 4 +- 5 files changed, 90 insertions(+), 76 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 2001d42a5eb..a214eb1c80b 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -450,20 +450,15 @@ int count_set_pose_transflags(Object *ob, for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { bone = pchan->bone; + bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR); if (PBONE_VISIBLE(arm, bone)) { if ((bone->flag & BONE_SELECTED)) { bone->flag |= BONE_TRANSFORM; } - else { - bone->flag &= ~BONE_TRANSFORM; - } bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM; bone->flag &= ~BONE_TRANSFORM_CHILD; } - else { - bone->flag &= ~BONE_TRANSFORM; - } } /* make sure no bone can be transformed when a parent is transformed */ diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index cc023688c8e..0edf55ece7e 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -86,6 +86,7 @@ static void add_pose_transdata( td->flag |= TD_NO_LOC; } + td->extra = pchan; td->protectflag = pchan->protectflag; td->loc = pchan->loc; @@ -364,7 +365,7 @@ static short pose_grab_with_ik(Main *bmain, Object *ob) * (but they must be selected, and only one ik-solver per chain should get added) */ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { if (pchan->bone->layer & arm->layer) { - if (pchan->bone->flag & BONE_SELECTED) { + if (pchan->bone->flag & (BONE_SELECTED | BONE_TRANSFORM_MIRROR)) { /* Rule: no IK for solitatry (unconnected) bones */ for (bonec = pchan->bone->childbase.first; bonec; bonec = bonec->next) { if (bonec->flag & BONE_CONNECTED) { @@ -379,7 +380,7 @@ static short pose_grab_with_ik(Main *bmain, Object *ob) if (pchan->parent) { /* only adds if there's no IK yet (and no parent bone was selected) */ for (parent = pchan->parent; parent; parent = parent->parent) { - if (parent->bone->flag & BONE_SELECTED) { + if (parent->bone->flag & (BONE_SELECTED | BONE_TRANSFORM_MIRROR)) { break; } } @@ -513,14 +514,6 @@ void createTransPose(TransInfo *t) } } - /* do we need to add temporal IK chains? */ - if ((pose->flag & POSE_AUTO_IK) && t->mode == TFM_TRANSLATION) { - if (pose_grab_with_ik(bmain, ob)) { - t->flag |= T_AUTOIK; - has_translate_rotate[0] = true; - } - } - if (mirror) { int total_mirrored = 0; for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { @@ -541,16 +534,6 @@ void createTransPose(TransInfo *t) } } - /* if there are no translatable bones, do rotation */ - if ((t->mode == TFM_TRANSLATION) && !has_translate_rotate[0]) { - if (has_translate_rotate[1]) { - t->mode = TFM_ROTATION; - } - else { - t->mode = TFM_RESIZE; - } - } - FOREACH_TRANS_DATA_CONTAINER (t, tc) { if (tc->data_len == 0) { continue; @@ -582,20 +565,32 @@ void createTransPose(TransInfo *t) td->val = NULL; } - /* use pose channels to fill trans data */ - td = tc->data; - for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->bone->flag & BONE_TRANSFORM) { - add_pose_transdata(t, pchan, ob, tc, td); - - if (mirror) { + if (mirror) { + for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) { + if (pchan->bone->flag & BONE_TRANSFORM) { bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name); if (pchan_mirror) { + pchan_mirror->bone->flag |= BONE_TRANSFORM_MIRROR; pose_mirror_info_init(&pid[pid_index], pchan_mirror, pchan, is_mirror_relative); pid_index++; } } + } + } + /* do we need to add temporal IK chains? */ + if ((pose->flag & POSE_AUTO_IK) && t->mode == TFM_TRANSLATION) { + if (pose_grab_with_ik(bmain, ob)) { + t->flag |= T_AUTOIK; + has_translate_rotate[0] = true; + } + } + + /* use pose channels to fill trans data */ + td = tc->data; + for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + if (pchan->bone->flag & BONE_TRANSFORM) { + add_pose_transdata(t, pchan, ob, tc, td); td++; } } @@ -603,10 +598,20 @@ void createTransPose(TransInfo *t) if (td != (tc->data + tc->data_len)) { BKE_report(t->reports, RPT_DEBUG, "Bone selection count error"); } + } - /* initialize initial auto=ik chainlen's? */ - if (t->flag & T_AUTOIK) { - transform_autoik_update(t, 0); + /* initialize initial auto=ik chainlen's? */ + if (t->flag & T_AUTOIK) { + transform_autoik_update(t, 0); + } + + /* if there are no translatable bones, do rotation */ + if ((t->mode == TFM_TRANSLATION) && !has_translate_rotate[0]) { + if (has_translate_rotate[1]) { + t->mode = TFM_ROTATION; + } + else { + t->mode = TFM_RESIZE; } } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 9031dc06e3f..5595c3a0e38 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -31,6 +31,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_brush_types.h" +#include "DNA_constraint_types.h" #include "DNA_gpencil_types.h" #include "DNA_lattice_types.h" #include "DNA_screen_types.h" @@ -785,50 +786,61 @@ static void recalcData_spaceclip(TransInfo *t) * if pose bone (partial) selected, copy data. * context; posemode armature, with mirror editing enabled. * - * \param pid: Optional, apply relative transform when set. + * \param pid: Optional, apply relative transform when set (has no effect on mirrored bones). */ -static void pose_transform_mirror_update(Object *ob, PoseInitData_Mirror *pid) +static void pose_transform_mirror_update(TransInfo *t, + TransDataContainer *tc, + Object *ob, + PoseInitData_Mirror *pid) { float flip_mtx[4][4]; unit_m4(flip_mtx); flip_mtx[0][0] = -1; - for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig; - pchan_orig = pchan_orig->next) { - /* Clear the MIRROR flag from previous runs */ - pchan_orig->bone->flag &= ~BONE_TRANSFORM_MIRROR; - } - - for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig; - pchan_orig = pchan_orig->next) { - /* no layer check, correct mirror is more important */ - if (pchan_orig->bone->flag & BONE_TRANSFORM) { - bPoseChannel *pchan = BKE_pose_channel_get_mirrored(ob->pose, pchan_orig->name); - - if (pchan) { - /* also do bbone scaling */ - pchan->bone->xwidth = pchan_orig->bone->xwidth; - pchan->bone->zwidth = pchan_orig->bone->zwidth; - - /* we assume X-axis flipping for now */ - pchan->curve_in_x = pchan_orig->curve_in_x * -1; - pchan->curve_out_x = pchan_orig->curve_out_x * -1; - pchan->roll1 = pchan_orig->roll1 * -1; // XXX? - pchan->roll2 = pchan_orig->roll2 * -1; // XXX? - - float pchan_mtx_final[4][4]; - BKE_pchan_to_mat4(pchan_orig, pchan_mtx_final); - mul_m4_m4m4(pchan_mtx_final, pchan_mtx_final, flip_mtx); - mul_m4_m4m4(pchan_mtx_final, flip_mtx, pchan_mtx_final); - if (pid) { - mul_m4_m4m4(pchan_mtx_final, pid->offset_mtx, pchan_mtx_final); - pid++; - } - BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false); + TransData *td = tc->data; + for (int i = tc->data_len; i--; td++) { + bPoseChannel *pchan_orig = td->extra; + BLI_assert(pchan_orig->bone->flag & BONE_TRANSFORM); + /* No layer check, correct mirror is more important. */ + bPoseChannel *pchan = BKE_pose_channel_get_mirrored(ob->pose, pchan_orig->name); + if (pchan == NULL) { + continue; + } + + /* Also do bbone scaling. */ + pchan->bone->xwidth = pchan_orig->bone->xwidth; + pchan->bone->zwidth = pchan_orig->bone->zwidth; - /* set flag to let autokeyframe know to keyframe the mirrred bone */ - pchan->bone->flag |= BONE_TRANSFORM_MIRROR; + /* We assume X-axis flipping for now. */ + pchan->curve_in_x = pchan_orig->curve_in_x * -1; + pchan->curve_out_x = pchan_orig->curve_out_x * -1; + pchan->roll1 = pchan_orig->roll1 * -1; // XXX? + pchan->roll2 = pchan_orig->roll2 * -1; // XXX? + + float pchan_mtx_final[4][4]; + BKE_pchan_to_mat4(pchan_orig, pchan_mtx_final); + mul_m4_m4m4(pchan_mtx_final, pchan_mtx_final, flip_mtx); + mul_m4_m4m4(pchan_mtx_final, flip_mtx, pchan_mtx_final); + if (pid) { + mul_m4_m4m4(pchan_mtx_final, pid->offset_mtx, pchan_mtx_final); + } + BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false); + + /* In this case we can do target-less IK grabbing. */ + if (t->mode == TFM_TRANSLATION) { + bKinematicConstraint *data = has_targetless_ik(pchan); + if (data == NULL) { + continue; } + mul_v3_m4v3(data->grabtarget, flip_mtx, td->loc); + if (pid) { + /* TODO(germano): Realitve Mirror support */ + } + data->flag |= CONSTRAINT_IK_AUTO; + } + + if (pid) { + pid++; } } } @@ -1045,7 +1057,7 @@ static void recalcData_objects(TransInfo *t) DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); bPose *pose = ob->pose; if (arm->flag & ARM_MIRROR_EDIT || pose->flag & POSE_MIRROR_EDIT) { - pose_transform_mirror_update(ob, NULL); + pose_transform_mirror_update(t, tc, ob, NULL); } } } @@ -1063,7 +1075,7 @@ static void recalcData_objects(TransInfo *t) if (pose->flag & POSE_MIRROR_RELATIVE) { pid = tc->custom.type.data; } - pose_transform_mirror_update(ob, pid); + pose_transform_mirror_update(t, tc, ob, pid); } else { restoreMirrorPoseBones(tc); diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 3159464072e..1952a2c862e 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -413,7 +413,7 @@ static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it) int total = 0; for (bone = lb->first; bone; bone = bone->next) { - bone->flag &= ~BONE_TRANSFORM; + bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR); do_next = do_it; if (do_it) { if (bone->layer & arm->layer) { diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index 8c4b7dd52d9..43d0402d00a 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -1663,7 +1663,9 @@ static void rna_def_pose(BlenderRNA *brna) prop = RNA_def_property(srna, "use_mirror_relative", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", POSE_MIRROR_RELATIVE); RNA_def_property_ui_text( - prop, "Relative Mirror", "Apply relative transformations in X-mirror mode"); + prop, + "Relative Mirror", + "Apply relative transformations in X-mirror mode (not supported with Auto IK)"); RNA_def_struct_path_func(srna, "rna_Pose_path"); RNA_def_property_update(prop, 0, "rna_Pose_update"); RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); -- cgit v1.2.3