Anim: Don't use keying sets when inserting keyframes during autokeying #115522

Merged
Christoph Lendenfeld merged 9 commits from ChrisLend/blender:autokey_remove_keying_sets into main 2023-12-14 09:04:20 +01:00
4 changed files with 78 additions and 151 deletions

View File

@ -139,13 +139,10 @@ 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, ViewLayer *view_layer, Object *ob, eTfmMode tmode);
void autokeyframe_object(bContext *C, Scene *scene, Object *ob);
nathanvegdahl marked this conversation as resolved
Review

Add documentation for this. I think it would be especially useful for the doc comments of this and autokeyframe_pose() to make it clear what the difference between them is, and what their respective responsibilities are.

Add documentation for this. I think it would be especially useful for the doc comments of this and `autokeyframe_pose()` to make it clear what the difference between them is, and what their respective responsibilities are.

well honestly I am not quite sure what the differences are yet. I realized there was this duplication when I moved all the functions into the same file. Once the refactoring is complete, it may be we can merge the functions

well honestly I am not quite sure what the differences are yet. I realized there was this duplication when I moved all the functions into the same file. Once the refactoring is complete, it may be we can merge the functions
/**
* Auto-keyframing feature - for objects
nathanvegdahl marked this conversation as resolved
Review

"for objects" -> "for poses" (presumably).

"for objects" -> "for poses" (presumably).

This comment was moved as is when I moved the code. My best guess is that it was originally copy pasted from the autokeyframe_object function
Edit: I'll make a separate PR for this. No point in diluting the intent of this one

This comment was moved as is when I moved the code. My best guess is that it was originally copy pasted from the `autokeyframe_object` function Edit: I'll make a separate PR for this. No point in diluting the intent of this one
Review

Oh, interesting. Yeah, I think making a separate PR for the documentation changes/additions after more refactoring is fine. Maybe just add a TODO to update/add the docs, then?

Oh, interesting. Yeah, I think making a separate PR for the documentation changes/additions after more refactoring is fine. Maybe just add a TODO to update/add the docs, then?

actually I think the diff had us fooled here.
The docstring for autokeyframe_pose mentions for poses/pose-channels but the code was folded in a confusing way
Anyway I noticed the docstring still mentioned the tmode param. I removed that now

actually I think the diff had us fooled here. The docstring for `autokeyframe_pose` mentions `for poses/pose-channels` but the code was folded in a confusing way Anyway I noticed the docstring still mentioned the `tmode` param. I removed that now
*
* \param tmode: A transform mode.
*
* \note Context may not always be available,
* so must check before using it as it's a luxury for a few cases.
*/
@ -154,14 +151,12 @@ bool autokeyframe_pchan(bContext *C, Scene *scene, Object *ob, bPoseChannel *pch
/**
* Auto-keyframing feature - for poses/pose-channels
*
* \param tmode: A transform mode.
*
* targetless_ik: has targetless ik been done on any channels?
*
* \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, int tmode, short targetless_ik);
void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, short targetless_ik);
/**
* Use for auto-key-framing.
* \param only_if_property_keyed: if true, auto-key-framing only creates keyframes on already keyed

View File

@ -82,10 +82,20 @@ bool autokeyframe_cfra_can_key(const Scene *scene, ID *id)
return true;
}
void autokeyframe_object(
bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, const eTfmMode tmode)
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)
{
/* TODO: this should probably be done per channel instead. */
ID *id = &ob->id;
if (!autokeyframe_cfra_can_key(scene, id)) {
return;
@ -96,10 +106,9 @@ void autokeyframe_object(
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
depsgraph, BKE_scene_frame_get(scene));
eInsertKeyFlags flag = eInsertKeyFlags(0);
/* Get flags used for inserting keyframes. */
flag = ANIM_get_keyframing_flags(scene, true);
const eInsertKeyFlags flag = ANIM_get_keyframing_flags(scene, true);
nathanvegdahl marked this conversation as resolved Outdated

I think this can be const.

I think this can be const.

well spotted

well spotted
/* Add data-source override for the object. */
blender::Vector<PointerRNA> sources;
@ -112,9 +121,10 @@ void autokeyframe_object(
*/
ANIM_apply_keyingset(
C, &sources, active_ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
return;
}
else if (is_autokey_flag(scene, AUTOKEY_FLAG_INSERTAVAILABLE)) {
if (is_autokey_flag(scene, AUTOKEY_FLAG_INSERTAVAILABLE)) {
/* Only key on available channels. */
AnimData *adt = ob->adt;
ToolSettings *ts = scene->toolsettings;
@ -134,64 +144,22 @@ void autokeyframe_object(
flag);
}
}
return;
}
else if (is_autokey_flag(scene, AUTOKEY_FLAG_INSERTNEEDED)) {
bool do_loc = false, do_rot = false, do_scale = false;
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"};
nathanvegdahl marked this conversation as resolved
Review

Should this respect the "Default Key Channels", like manual keying does? Not saying it should, just double-checking.

Should this respect the "Default Key Channels", like manual keying does? Not saying it should, just double-checking.

I'd argue no. Auto-keying and manual-keying are two very different concepts and having the Default channels influence auto-keying would be quite annoying I think

I'd argue no. Auto-keying and manual-keying are two very different concepts and having the Default channels influence auto-keying would be quite annoying I think
Review

Makes sense! Thanks for the explanation. :-)

Makes sense! Thanks for the explanation. :-)
Main *bmain = CTX_data_main(C);
/* Filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D). */
if (tmode == TFM_TRANSLATION) {
do_loc = true;
}
else if (ELEM(tmode, TFM_ROTATION, 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)) {
do_loc = true;
}
}
else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
do_loc = true;
}
if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
do_rot = true;
}
}
else if (tmode == 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)) {
do_loc = true;
}
}
else if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CURSOR) {
do_loc = true;
}
if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
do_scale = true;
}
}
if (do_loc) {
KeyingSet *ks = ANIM_builtin_keyingset_get_named(ANIM_KS_LOCATION_ID);
ANIM_apply_keyingset(C, &sources, ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
}
if (do_rot) {
KeyingSet *ks = ANIM_builtin_keyingset_get_named(ANIM_KS_ROTATION_ID);
ANIM_apply_keyingset(C, &sources, ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
}
if (do_scale) {
KeyingSet *ks = ANIM_builtin_keyingset_get_named(ANIM_KS_SCALING_ID);
ANIM_apply_keyingset(C, &sources, ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
}
}
/* Insert keyframe in all (transform) channels. */
else {
KeyingSet *ks = ANIM_builtin_keyingset_get_named(ANIM_KS_LOC_ROT_SCALE_ID);
ANIM_apply_keyingset(C, &sources, ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
for (PointerRNA ptr : sources) {
insert_key_rna(&ptr,
rna_paths.as_span(),
scene_frame,
flag,
eBezTriple_KeyframeType(scene->toolsettings->keyframe_type),
bmain,
reports);
}
}
@ -231,7 +199,7 @@ bool autokeyframe_pchan(bContext *C, Scene *scene, Object *ob, bPoseChannel *pch
return true;
}
void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short targetless_ik)
void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, short targetless_ik)
{
Main *bmain = CTX_data_main(C);
ID *id = &ob->id;
@ -247,16 +215,16 @@ void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short t
ToolSettings *ts = scene->toolsettings;
KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(
depsgraph, BKE_scene_frame_get(scene));
eInsertKeyFlags flag = eInsertKeyFlags(0);
const float scene_frame = BKE_scene_frame_get(scene);
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
scene_frame);
/* flag is initialized from UserPref keyframing settings
* - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get
* visual keyframes even if flag not set, as it's not that useful otherwise
* (for quick animation recording)
*/
flag = ANIM_get_keyframing_flags(scene, true);
eInsertKeyFlags flag = ANIM_get_keyframing_flags(scene, true);
if (targetless_ik) {
flag |= INSERTKEY_MATRIX;
@ -278,87 +246,51 @@ void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short t
/* 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? */
else 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(pchan->name)];
if (!BLI_str_quoted_substr(fcu->rna_path, "bones[", pchan_name, sizeof(pchan_name))) {
continue;
}
if (blender::animrig::is_autokey_flag(scene, AUTOKEY_FLAG_INSERTAVAILABLE)) {
if (!act) {
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, 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);
}
}
continue;
}
/* only insert keyframe if needed? */
else if (blender::animrig::is_autokey_flag(scene, AUTOKEY_FLAG_INSERTNEEDED)) {
bool do_loc = false, do_rot = false, do_scale = false;
/* Filter the conditions when this happens
* (assume that 'curarea->spacetype == SPACE_VIEW3D'). */
if (tmode == TFM_TRANSLATION) {
if (targetless_ik) {
do_rot = true;
}
else {
do_loc = true;
}
}
else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
if (ELEM(scene->toolsettings->transform_pivot_point, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE))
{
do_loc = true;
}
if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
do_rot = true;
}
}
else if (tmode == TFM_RESIZE) {
if (ELEM(scene->toolsettings->transform_pivot_point, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE))
{
do_loc = true;
}
if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
do_scale = true;
}
}
if (do_loc) {
KeyingSet *ks = ANIM_builtin_keyingset_get_named(ANIM_KS_LOCATION_ID);
ANIM_apply_keyingset(C, &sources, ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
}
if (do_rot) {
KeyingSet *ks = ANIM_builtin_keyingset_get_named(ANIM_KS_ROTATION_ID);
ANIM_apply_keyingset(C, &sources, ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
}
if (do_scale) {
KeyingSet *ks = ANIM_builtin_keyingset_get_named(ANIM_KS_SCALING_ID);
ANIM_apply_keyingset(C, &sources, ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
}
}
/* insert keyframe in all (transform) channels */
else {
KeyingSet *ks = ANIM_builtin_keyingset_get_named(ANIM_KS_LOC_ROT_SCALE_ID);
ANIM_apply_keyingset(C, &sources, ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
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);
}
}
}

View File

@ -1326,7 +1326,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, t->mode, targetless_ik);
blender::animrig::autokeyframe_pose(t->context, t->scene, ob, targetless_ik);
}
if (motionpath_need_update_pose(t->scene, ob)) {
@ -1589,7 +1589,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, t->mode, targetless_ik);
blender::animrig::autokeyframe_pose(C, t->scene, ob, targetless_ik);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
else {

View File

@ -780,7 +780,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, t->view_layer, ob, t->mode);
blender::animrig::autokeyframe_object(t->context, t->scene, ob);
}
motionpath_update |= motionpath_need_update_object(t->scene, ob);
@ -855,7 +855,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, t->view_layer, ob, t->mode);
blender::animrig::autokeyframe_object(C, t->scene, ob);
}
motionpath_update |= motionpath_need_update_object(t->scene, ob);