Fix: Autokeyframe with Insert Needed with no keyframes
The issue occurs when auto-keyframe AND "Only Insert Needed" enabled. And only when no keyframes have been added yet. Before the commit that caused the issue, moving an object with `G` would create only location keyframes. After it would key all. That is because that commit removed the logic that checks the `eTfmMode` (Transform mode). That only works as long as there are already keyframes on the object/bone because the logic needs an existing value to compare against. In the case where the first keyframe is set, it would always key everything. The fix is to bring back the logic that checks the Transform mode and pass a `Span` of rna paths to the autokeyframe function. This restores the behavior. This still has the issue that "Only Insert Needed" behaves differently if keys exist vs inserting the first keys. While this isn't ideal, I don't see a way to get values of an object/bone before and after the transformation. We might be able to fix this in a future PR, but for now we restore the old behavior. Caused by #115522 Pull Request: https://projects.blender.org/blender/blender/pulls/116219
This commit is contained in:
parent
d37f9e6587
commit
614d7749df
|
@ -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<std::string> 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<std::string> 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
|
||||
|
|
|
@ -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<float> 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
|
||||
|
|
|
@ -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<float> 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
|
||||
|
|
|
@ -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<std::string> 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<std::string> 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<std::string> 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<PointerRNA> 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<PointerRNA> 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<std::string> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<std::string> get_affected_rna_paths_from_transform_mode(
|
||||
const eTfmMode tmode,
|
||||
ToolSettings *toolsettings,
|
||||
const blender::StringRef rotation_path,
|
||||
const bool targetless_ik)
|
||||
{
|
||||
blender::Vector<std::string> 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<std::string> 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 {
|
||||
|
|
|
@ -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<std::string> get_affected_rna_paths_from_transform_mode(
|
||||
const eTfmMode tmode,
|
||||
Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
Object *ob,
|
||||
const blender::StringRef rotation_path)
|
||||
{
|
||||
blender::Vector<std::string> 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<std::string> 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);
|
||||
|
|
Loading…
Reference in New Issue