Fix: make auto-keying reliably key all needed bone channels

This is a follow-up to #123998 which fixed autokeying on objects when
the "Only Insert Needed" user preference was enabled. This fixes an
essentially identical bug for auto-keying bones, but *also* fixes a
different-but-related bug unique to bone keying.

In the first bug the location channel would erroneously not get keyed
sometimes when the "Only Insert Needed" user preference was enabled.
This fixes that by passing in whether more than one bone is being keyed
or not, and using that to accurately determine if location actually
needs to be keyed.

In the second bug, the location channel would erroneously not get keyed
when "Auto IK" was used to transform bones. This fixes that by just
being over-conservative. This unforunately leads to more bones getting
their location channel keyed than needed when Auto IK is used, but this
is better than *failing* to key needed channels, which was the previous
behavior. I left a comment explaining the situation, along with a TODO
to address this in a more satisfying way in the future.

Pull Request: https://projects.blender.org/blender/blender/pulls/124054
This commit is contained in:
Nathan Vegdahl 2024-07-04 10:18:32 +02:00 committed by Nathan Vegdahl
parent 8bf4d3c33f
commit b31d34033a

@ -1271,35 +1271,57 @@ static blender::Vector<RNAPath> get_affected_rna_paths_from_transform_mode(
const eTfmMode tmode,
ToolSettings *toolsettings,
const blender::StringRef rotation_path,
const bool targetless_ik)
const bool targetless_ik,
const bool transforming_more_than_one_bone)
{
blender::Vector<RNAPath> rna_paths;
/* Handle the cases where we always need to key location, regardless of
* transform mode. */
if (transforming_more_than_one_bone &&
toolsettings->transform_pivot_point != V3D_AROUND_LOCAL_ORIGINS)
{
rna_paths.append({"location"});
}
else if (toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
rna_paths.append({"location"});
}
/* Handle the transform-mode-specific cases. */
switch (tmode) {
case TFM_TRANSLATION:
/* NOTE: this used to only add location if we weren't doing targetless IK.
* However, that was wrong because of the following situations:
*
* - The user can grab the *base* of the bone chain, in which case that
* bone's location does indeed get its location moved, and thus needs
* its location keyed.
* - The user can also have bones outside of a bone chain selected, in
* which case they get moved normally, and thus those outside-of-a-chain
* bones need their location keyed.
*
* So for now we're just adding location unconditionally. This
* unfortunately means that location gets keyed on a lot of bones that
* don't need it when doing targetless ik, but that's better than
* *failing* to key bones that *do* need it. Being precise and only adding
* location for the bones that really need it will require more
* information to be passed to this function.
*
* TODO: get the needed information and make this more precise. */
rna_paths.append_non_duplicates({"location"});
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"});
}
@ -1311,8 +1333,12 @@ static blender::Vector<RNAPath> get_affected_rna_paths_from_transform_mode(
return rna_paths;
}
static void autokeyframe_pose(
bContext *C, Scene *scene, Object *ob, short targetless_ik, const eTfmMode tmode)
static void autokeyframe_pose(bContext *C,
Scene *scene,
Object *ob,
short targetless_ik,
const eTfmMode tmode,
const bool transforming_more_than_one_bone)
{
bPose *pose = ob->pose;
@ -1328,8 +1354,11 @@ static void autokeyframe_pose(
eRotationModes(pchan->rotmode));
if (blender::animrig::is_keying_flag(scene, AUTOKEY_FLAG_INSERTNEEDED)) {
rna_paths = get_affected_rna_paths_from_transform_mode(
tmode, scene->toolsettings, rotation_path, targetless_ik);
rna_paths = get_affected_rna_paths_from_transform_mode(tmode,
scene->toolsettings,
rotation_path,
targetless_ik,
transforming_more_than_one_bone);
}
else {
rna_paths = {{"location"}, {rotation_path}, {"scale"}};
@ -1400,7 +1429,7 @@ static void recalcData_pose(TransInfo *t)
int targetless_ik = (t->flag & T_AUTOIK);
animrecord_check_state(t, &ob->id);
autokeyframe_pose(t->context, t->scene, ob, targetless_ik, t->mode);
autokeyframe_pose(t->context, t->scene, ob, targetless_ik, t->mode, t->data_len_all > 1);
}
if (motionpath_need_update_pose(t->scene, ob)) {
@ -1663,7 +1692,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)) {
autokeyframe_pose(C, t->scene, ob, targetless_ik, t->mode);
autokeyframe_pose(C, t->scene, ob, targetless_ik, t->mode, t->data_len_all > 1);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
else {