Fix: Autokeyframe with Insert Needed with no keyframes #116219
|
@ -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.
|
||||
Sybren A. Stüvel
commented
Same request as above, to document Same request as above, to document `rna_paths`. I think the rest is either already documented or clear enough from the context.
|
||||
*/
|
||||
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);
|
||||
Sybren A. Stüvel
commented
"Helper function to" can be removed; "Get the rna path for the given rotation mode." is clear enough. "Helper function to" can be removed; "Get the rna path for the given rotation mode." is clear enough.
|
||||
|
||||
} // 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)
|
||||
Sybren A. Stüvel
commented
Low prio: this might not need to be Not for this PR though, as just moving the function as-is is better here. Low prio: this might not need to be `std::string`, maybe `std::string_view` or `blender::StringRef` works just as well, and avoids a copy.
Not for this PR though, as just moving the function as-is is better here.
|
||||
{
|
||||
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,
|
||||
Sybren A. Stüvel
commented
This function now grabs stuff from the context and creates the
For this PR I think this is fine, but it might be worth looking into creating some This function now grabs stuff from the context and creates the `AnimationEvalContext` for every pose channel:
```cpp
ReportList *reports = CTX_wm_reports(C);
ToolSettings *ts = scene->toolsettings;
KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
const float scene_frame = BKE_scene_frame_get(scene);
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph, scene_frame);
```
For this PR I think this is fine, but it might be worth looking into creating some `AutoKeyframeContext` struct that contains all of those, and pass that into this function instead.
|
||||
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(
|
||||
Sybren A. Stüvel
commented
`rotation_path` can be a `blender::StringRef`.
|
||||
const eTfmMode tmode,
|
||||
ToolSettings *toolsettings,
|
||||
const blender::StringRef rotation_path,
|
||||
const bool targetless_ik)
|
||||
Sybren A. Stüvel
commented
This should be a This should be a `switch (tmode)` instead.
|
||||
{
|
||||
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)
|
||||
{
|
||||
Sybren A. Stüvel
commented
`const`, and possibly a `blender::StringRef`
|
||||
|
||||
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
|
||||
Sybren A. Stüvel
commented
The function name could be clearer. It's likely meant as "the RNA paths that were modified by the transform system", but that's only clear once you know what it does. Maybe This code also looks very much dependent on specifics of other areas of the code. I don't think we can totally avoid that without major rewrites of other areas. It would be nice, if it's doable, to add a comment here that explains which function(s) this logic should be in sync with. The function name could be clearer. It's likely meant as "the RNA paths that were modified by the transform system", but that's only clear once you know what it does. Maybe `rna_paths_touched_by_transform_system` or something along those lines?
This code also looks very much dependent on specifics of other areas of the code. I don't think we can totally avoid that without major rewrites of other areas. It would be nice, if it's doable, to add a comment here that explains which function(s) this logic should be in sync with.
named it About which functions this should be in sync with. Not sure what you mean. You mean that it needs to be in sync with the transform system in general? named it `get_affected_rna_paths_from_transform_mode` and also used a `switch` here instead of the if/else chain
About which functions this should be in sync with. Not sure what you mean. You mean that it needs to be in sync with the transform system in general?
Sybren A. Stüvel
commented
Yeah, and with the code as it is now, that's obvious enough 👍 Yeah, and with the code as it is now, that's obvious enough :+1:
|
||||
* 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);
|
||||
|
|
Maybe add some documentation for the
rna_paths
parameter. It's otherwise hard to know whether it's "always key all these paths" or "never key anything outside this set".