diff --git a/source/blender/animrig/ANIM_keyframing.hh b/source/blender/animrig/ANIM_keyframing.hh index fa0cbfa0a1b..17441b77d2e 100644 --- a/source/blender/animrig/ANIM_keyframing.hh +++ b/source/blender/animrig/ANIM_keyframing.hh @@ -142,7 +142,12 @@ bool is_autokey_flag(const Scene *scene, eKeyInsert_Flag flag); */ bool autokeyframe_cfra_can_key(const Scene *scene, ID *id); -void autokeyframe_object(bContext *C, Scene *scene, Object *ob); +/** + * Insert keyframes on the given object `ob` based on the auto-keying settings. + * + * \param rna_paths: Only inserts keys on those RNA paths. + */ +void autokeyframe_object(bContext *C, Scene *scene, Object *ob, Span rna_paths); /** * Auto-keyframing feature - for objects * @@ -154,12 +159,18 @@ bool autokeyframe_pchan(bContext *C, Scene *scene, Object *ob, bPoseChannel *pch /** * Auto-keyframing feature - for poses/pose-channels * - * targetless_ik: has targetless ik been done on any channels? + * \param targetless_ik: Has targetless ik been done on any channels? + * \param rna_paths: Only inserts keys on those RNA paths. * * \note Context may not always be available, * so must check before using it as it's a luxury for a few cases. */ -void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, short targetless_ik); +void autokeyframe_pose_channel(bContext *C, + Scene *scene, + Object *ob, + bPoseChannel *pose_channel, + Span rna_paths, + short targetless_ik); /** * Use for auto-key-framing. * \param only_if_property_keyed: if true, auto-key-framing only creates keyframes on already keyed diff --git a/source/blender/animrig/ANIM_rna.hh b/source/blender/animrig/ANIM_rna.hh index 831b2bad1ba..d2fcb8f24f0 100644 --- a/source/blender/animrig/ANIM_rna.hh +++ b/source/blender/animrig/ANIM_rna.hh @@ -9,6 +9,7 @@ */ #include "BLI_vector.hh" +#include "DNA_action_types.h" #include "RNA_types.hh" namespace blender::animrig { @@ -16,4 +17,7 @@ namespace blender::animrig { /** Get the values of the given property. Casts non-float properties to float. */ Vector get_rna_values(PointerRNA *ptr, PropertyRNA *prop); +/** Get the rna path for the given rotation mode. */ +std::string get_rotation_mode_path(eRotationModes rotation_mode); + } // namespace blender::animrig diff --git a/source/blender/animrig/intern/anim_rna.cc b/source/blender/animrig/intern/anim_rna.cc index 2b0b8176550..91393288928 100644 --- a/source/blender/animrig/intern/anim_rna.cc +++ b/source/blender/animrig/intern/anim_rna.cc @@ -8,6 +8,7 @@ #include "ANIM_rna.hh" #include "BLI_vector.hh" +#include "DNA_action_types.h" #include "RNA_access.hh" namespace blender::animrig { @@ -68,4 +69,16 @@ Vector get_rna_values(PointerRNA *ptr, PropertyRNA *prop) return values; } + +std::string get_rotation_mode_path(const eRotationModes rotation_mode) +{ + switch (rotation_mode) { + case ROT_MODE_QUAT: + return "rotation_quaternion"; + case ROT_MODE_AXISANGLE: + return "rotation_axis_angle"; + default: + return "rotation_euler"; + } +} } // namespace blender::animrig diff --git a/source/blender/animrig/intern/keyframing_auto.cc b/source/blender/animrig/intern/keyframing_auto.cc index 79a293a79e0..0eae66823e2 100644 --- a/source/blender/animrig/intern/keyframing_auto.cc +++ b/source/blender/animrig/intern/keyframing_auto.cc @@ -26,6 +26,7 @@ #include "ED_transform.hh" #include "ANIM_keyframing.hh" +#include "ANIM_rna.hh" #include "WM_api.hh" #include "WM_types.hh" @@ -82,19 +83,7 @@ bool autokeyframe_cfra_can_key(const Scene *scene, ID *id) return true; } -static std::string get_rotation_mode_path(const eRotationModes rotmode) -{ - switch (rotmode) { - case ROT_MODE_QUAT: - return "rotation_quaternion"; - case ROT_MODE_AXISANGLE: - return "rotation_axis_angle"; - default: - return "rotation_euler"; - } -} - -void autokeyframe_object(bContext *C, Scene *scene, Object *ob) +void autokeyframe_object(bContext *C, Scene *scene, Object *ob, Span rna_paths) { ID *id = &ob->id; if (!autokeyframe_cfra_can_key(scene, id)) { @@ -148,13 +137,11 @@ void autokeyframe_object(bContext *C, Scene *scene, Object *ob) } const float scene_frame = BKE_scene_frame_get(scene); - std::string rotation_rna_path = get_rotation_mode_path(eRotationModes(ob->rotmode)); - Vector rna_paths = {"location", rotation_rna_path, "scale"}; Main *bmain = CTX_data_main(C); for (PointerRNA ptr : sources) { insert_key_rna(&ptr, - rna_paths.as_span(), + rna_paths, scene_frame, flag, eBezTriple_KeyframeType(scene->toolsettings->keyframe_type), @@ -199,13 +186,17 @@ bool autokeyframe_pchan(bContext *C, Scene *scene, Object *ob, bPoseChannel *pch return true; } -void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, short targetless_ik) +void autokeyframe_pose_channel(bContext *C, + Scene *scene, + Object *ob, + bPoseChannel *pose_channel, + Span rna_paths, + short targetless_ik) { Main *bmain = CTX_data_main(C); ID *id = &ob->id; AnimData *adt = ob->adt; bAction *act = (adt) ? adt->action : nullptr; - bPose *pose = ob->pose; if (!blender::animrig::autokeyframe_cfra_can_key(scene, id)) { return; @@ -230,68 +221,57 @@ void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, short targetless_i flag |= INSERTKEY_MATRIX; } - LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) { - if ((pchan->bone->flag & BONE_TRANSFORM) == 0 && - !((pose->flag & POSE_MIRROR_EDIT) && (pchan->bone->flag & BONE_TRANSFORM_MIRROR))) - { - continue; + blender::Vector sources; + /* Add data-source override for the camera object. */ + ANIM_relative_keyingset_add_source(sources, id, &RNA_PoseBone, pose_channel); + + /* only insert into active keyingset? */ + if (blender::animrig::is_autokey_flag(scene, AUTOKEY_FLAG_ONLYKEYINGSET) && (active_ks)) { + /* Run the active Keying Set on the current data-source. */ + ANIM_apply_keyingset( + C, &sources, active_ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time); + return; + } + + /* only insert into available channels? */ + if (blender::animrig::is_autokey_flag(scene, AUTOKEY_FLAG_INSERTAVAILABLE)) { + if (!act) { + return; } - - blender::Vector sources; - /* Add data-source override for the camera object. */ - ANIM_relative_keyingset_add_source(sources, id, &RNA_PoseBone, pchan); - - /* only insert into active keyingset? */ - if (blender::animrig::is_autokey_flag(scene, AUTOKEY_FLAG_ONLYKEYINGSET) && (active_ks)) { - /* Run the active Keying Set on the current data-source. */ - ANIM_apply_keyingset( - C, &sources, active_ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time); - continue; - } - - /* only insert into available channels? */ - if (blender::animrig::is_autokey_flag(scene, AUTOKEY_FLAG_INSERTAVAILABLE)) { - if (!act) { + LISTBASE_FOREACH (FCurve *, fcu, &act->curves) { + /* only insert keyframes for this F-Curve if it affects the current bone */ + char pchan_name[sizeof(pose_channel->name)]; + if (!BLI_str_quoted_substr(fcu->rna_path, "bones[", pchan_name, sizeof(pchan_name))) { continue; } - LISTBASE_FOREACH (FCurve *, fcu, &act->curves) { - /* only insert keyframes for this F-Curve if it affects the current bone */ - char pchan_name[sizeof(pchan->name)]; - if (!BLI_str_quoted_substr(fcu->rna_path, "bones[", pchan_name, sizeof(pchan_name))) { - continue; - } - /* only if bone name matches too... - * NOTE: this will do constraints too, but those are ok to do here too? - */ - if (STREQ(pchan_name, pchan->name)) { - blender::animrig::insert_keyframe(bmain, - reports, - id, - act, - ((fcu->grp) ? (fcu->grp->name) : (nullptr)), - fcu->rna_path, - fcu->array_index, - &anim_eval_context, - eBezTriple_KeyframeType(ts->keyframe_type), - flag); - } + /* only if bone name matches too... + * NOTE: this will do constraints too, but those are ok to do here too? + */ + if (STREQ(pchan_name, pose_channel->name)) { + blender::animrig::insert_keyframe(bmain, + reports, + id, + act, + ((fcu->grp) ? (fcu->grp->name) : (nullptr)), + fcu->rna_path, + fcu->array_index, + &anim_eval_context, + eBezTriple_KeyframeType(ts->keyframe_type), + flag); } - continue; } + return; + } - Main *bmain = CTX_data_main(C); - std::string rotation_rna_path = get_rotation_mode_path(eRotationModes(pchan->rotmode)); - Vector rna_paths = {"location", rotation_rna_path, "scale"}; - for (PointerRNA &ptr : sources) { - insert_key_rna(&ptr, - rna_paths, - scene_frame, - flag, - eBezTriple_KeyframeType(scene->toolsettings->keyframe_type), - bmain, - reports); - } + for (PointerRNA &ptr : sources) { + insert_key_rna(&ptr, + rna_paths, + scene_frame, + flag, + eBezTriple_KeyframeType(scene->toolsettings->keyframe_type), + bmain, + reports); } } diff --git a/source/blender/editors/transform/transform_convert_armature.cc b/source/blender/editors/transform/transform_convert_armature.cc index 04571cd168b..4d51932bce1 100644 --- a/source/blender/editors/transform/transform_convert_armature.cc +++ b/source/blender/editors/transform/transform_convert_armature.cc @@ -39,6 +39,7 @@ #include "ANIM_bone_collections.hh" #include "ANIM_keyframing.hh" +#include "ANIM_rna.hh" #include "transform.hh" #include "transform_orientations.hh" @@ -1266,6 +1267,81 @@ static void restoreMirrorPoseBones(TransDataContainer *tc) } } +/* Given the transform mode `tmode` return a Vector of RNA paths that were possibly modified during + * that transformation. */ +static blender::Vector get_affected_rna_paths_from_transform_mode( + const eTfmMode tmode, + ToolSettings *toolsettings, + const blender::StringRef rotation_path, + const bool targetless_ik) +{ + blender::Vector rna_paths; + switch (tmode) { + case TFM_TRANSLATION: + if (targetless_ik) { + rna_paths.append(rotation_path); + } + else { + rna_paths.append("location"); + } + break; + + case TFM_ROTATION: + case TFM_TRACKBALL: + if (ELEM(toolsettings->transform_pivot_point, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE)) { + rna_paths.append("location"); + } + + if ((toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) { + rna_paths.append(rotation_path); + } + break; + + case TFM_RESIZE: + if (ELEM(toolsettings->transform_pivot_point, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE)) { + rna_paths.append("location"); + } + + if ((toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) { + rna_paths.append("scale"); + } + break; + + default: + break; + } + return rna_paths; +} + +static void autokeyframe_pose( + bContext *C, Scene *scene, Object *ob, short targetless_ik, const eTfmMode tmode) +{ + + bPose *pose = ob->pose; + LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) { + if ((pchan->bone->flag & BONE_TRANSFORM) == 0 && + !((pose->flag & POSE_MIRROR_EDIT) && (pchan->bone->flag & BONE_TRANSFORM_MIRROR))) + { + continue; + } + + blender::Vector rna_paths; + const blender::StringRef rotation_path = blender::animrig::get_rotation_mode_path( + eRotationModes(pchan->rotmode)); + + if (blender::animrig::is_autokey_flag(scene, AUTOKEY_FLAG_INSERTNEEDED)) { + rna_paths = get_affected_rna_paths_from_transform_mode( + tmode, scene->toolsettings, rotation_path, targetless_ik); + } + else { + rna_paths = {"location", rotation_path, "scale"}; + } + + blender::animrig::autokeyframe_pose_channel( + C, scene, ob, pchan, rna_paths.as_span(), targetless_ik); + } +} + static void recalcData_pose(TransInfo *t) { if (t->mode == TFM_BONESIZE) { @@ -1326,7 +1402,7 @@ static void recalcData_pose(TransInfo *t) int targetless_ik = (t->flag & T_AUTOIK); animrecord_check_state(t, &ob->id); - blender::animrig::autokeyframe_pose(t->context, t->scene, ob, targetless_ik); + autokeyframe_pose(t->context, t->scene, ob, targetless_ik, t->mode); } if (motionpath_need_update_pose(t->scene, ob)) { @@ -1589,7 +1665,7 @@ static void special_aftertrans_update__pose(bContext *C, TransInfo *t) /* automatic inserting of keys and unkeyed tagging - * only if transform wasn't canceled (or TFM_DUMMY) */ if (!canceled && (t->mode != TFM_DUMMY)) { - blender::animrig::autokeyframe_pose(C, t->scene, ob, targetless_ik); + autokeyframe_pose(C, t->scene, ob, targetless_ik, t->mode); DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); } else { diff --git a/source/blender/editors/transform/transform_convert_object.cc b/source/blender/editors/transform/transform_convert_object.cc index 616cecf9881..9761d7a3334 100644 --- a/source/blender/editors/transform/transform_convert_object.cc +++ b/source/blender/editors/transform/transform_convert_object.cc @@ -25,6 +25,7 @@ #include "BKE_scene.h" #include "ANIM_keyframing.hh" +#include "ANIM_rna.hh" #include "ED_keyframing.hh" #include "ED_object.hh" @@ -755,6 +756,80 @@ static bool motionpath_need_update_object(Scene *scene, Object *ob) /** \name Recalc Data object * \{ */ +/* Given the transform mode `tmode` return a Vector of RNA paths that were possibly modified during + * that transformation. */ +static blender::Vector get_affected_rna_paths_from_transform_mode( + const eTfmMode tmode, + Scene *scene, + ViewLayer *view_layer, + Object *ob, + const blender::StringRef rotation_path) +{ + blender::Vector rna_paths; + switch (tmode) { + case TFM_TRANSLATION: + rna_paths.append("location"); + break; + + case TFM_ROTATION: + case TFM_TRACKBALL: + if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) { + BKE_view_layer_synced_ensure(scene, view_layer); + if (ob != BKE_view_layer_active_object_get(view_layer)) { + rna_paths.append("location"); + } + } + else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) { + rna_paths.append("location"); + } + + if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) { + rna_paths.append(rotation_path); + } + break; + + case TFM_RESIZE: + if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) { + BKE_view_layer_synced_ensure(scene, view_layer); + if (ob != BKE_view_layer_active_object_get(view_layer)) { + rna_paths.append("location"); + } + } + else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) { + rna_paths.append("location"); + } + + if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) { + rna_paths.append("scale"); + } + break; + + default: + rna_paths.append("location"); + rna_paths.append(rotation_path); + rna_paths.append("scale"); + } + + return rna_paths; +} + +static void autokeyframe_object(bContext *C, Scene *scene, Object *ob, const eTfmMode tmode) +{ + blender::Vector rna_paths; + ViewLayer *view_layer = CTX_data_view_layer(C); + const blender::StringRef rotation_path = blender::animrig::get_rotation_mode_path( + eRotationModes(ob->rotmode)); + + if (blender::animrig::is_autokey_flag(scene, AUTOKEY_FLAG_INSERTNEEDED)) { + rna_paths = get_affected_rna_paths_from_transform_mode( + tmode, scene, view_layer, ob, rotation_path); + } + else { + rna_paths = {"location", rotation_path, "scale"}; + } + blender::animrig::autokeyframe_object(C, scene, ob, rna_paths.as_span()); +} + static void recalcData_objects(TransInfo *t) { bool motionpath_update = false; @@ -780,7 +855,7 @@ static void recalcData_objects(TransInfo *t) * (FPoints) instead of keyframes? */ if ((t->animtimer) && blender::animrig::is_autokey_on(t->scene)) { animrecord_check_state(t, &ob->id); - blender::animrig::autokeyframe_object(t->context, t->scene, ob); + autokeyframe_object(t->context, t->scene, ob, t->mode); } motionpath_update |= motionpath_need_update_object(t->scene, ob); @@ -855,7 +930,7 @@ static void special_aftertrans_update__object(bContext *C, TransInfo *t) /* Set auto-key if necessary. */ if (!canceled) { - blender::animrig::autokeyframe_object(C, t->scene, ob); + autokeyframe_object(C, t->scene, ob, t->mode); } motionpath_update |= motionpath_need_update_object(t->scene, ob);