Fix: Follow Curve constraint/parenting doesn't animate with layered actions
Both the Follow Curve constraint and parenting with the follow curve option require a property on the Curve ID to be animated if the user wants the follower object to animate along the curve. However, the fcurve for this was always getting created as a legacy action fcurve, regardless of whether the action was actually legacy or not. If the action was layered, this resulted in the follower object not animating along the path. The underlying issue was that the code that created the fcurve was using `action_fcurve_ensure()`, which hadn't yet been updated to work correctly with layered actions, and thus the fcurve was created as if the action was legacy. This commit fixes that by updating `action_fcurve_ensure()` to work with Baklava phase-1 layered actions in limited circumstances, and also ensuring that the follow curve code passes an appropriate ID RNA pointer (required to find/create an appropriate Slot). Pull Request: https://projects.blender.org/blender/blender/pulls/124353
This commit is contained in:
committed by
Nathan Vegdahl
parent
b76a1db907
commit
cb38406a94
@@ -766,9 +766,22 @@ Vector<const FCurve *> fcurves_all(const Action &action);
|
||||
Vector<FCurve *> fcurves_all(Action &action);
|
||||
|
||||
/**
|
||||
* Get (or add relevant data to be able to do so) an F-Curve from the given Action,
|
||||
* for the given animated data-block. This assumes that all the destinations are valid.
|
||||
* \param ptr: can be a null pointer.
|
||||
* Get (or add relevant data to be able to do so) an F-Curve from the given
|
||||
* Action. This assumes that all the destinations are valid.
|
||||
*
|
||||
* NOTE: this function is primarily intended for use with legacy actions, but
|
||||
* for reasons of expedience it now also works with layered actions under the
|
||||
* following limited circumstances: `ptr` must be non-null and must have an
|
||||
* `owner_id` that already uses `act`. Otherwise this function will return
|
||||
* nullptr for layered actions. See the comments in the implementation for more
|
||||
* details.
|
||||
*
|
||||
* \param ptr: RNA pointer for the struct the fcurve is being looked up/created
|
||||
* for. For legacy actions this is optional and may be null.
|
||||
*
|
||||
* \param fcurve_descriptor: description of the fcurve to lookup/create. Note
|
||||
* that this is *not* relative to `ptr` (e.g. if `ptr` is not an ID). It should
|
||||
* contain the exact data path of the fcurve to be looked up/created.
|
||||
*/
|
||||
FCurve *action_fcurve_ensure(Main *bmain,
|
||||
bAction *act,
|
||||
|
||||
@@ -1311,6 +1311,46 @@ FCurve *action_fcurve_ensure(Main *bmain,
|
||||
if (act == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
Action &action = act->wrap();
|
||||
|
||||
if (USER_EXPERIMENTAL_TEST(&U, use_animation_baklava) && action.is_action_layered()) {
|
||||
/* NOTE: for layered actions we require the following:
|
||||
*
|
||||
* - `ptr` is non-null.
|
||||
* - `ptr` has an `owner_id` that already uses `act`.
|
||||
*
|
||||
* This isn't for any principled reason, but rather is because adding
|
||||
* support for layered actions to this function was a fix to make Follow
|
||||
* Path animation work properly with layered actions (see PR #124353), and
|
||||
* those are the requirements the Follow Path code conveniently met.
|
||||
* Moreover those requirements were also already met by the other call sites
|
||||
* that potentially call this function with layered actions.
|
||||
*
|
||||
* Trying to puzzle out what "should" happen when these requirements don't
|
||||
* hold, or if this is even the best place to handle the layered action
|
||||
* cases at all, was leading to discussion of larger changes than made sense
|
||||
* to tackle at that point. */
|
||||
BLI_assert(ptr != nullptr);
|
||||
if (ptr == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
AnimData *adt = BKE_animdata_from_id(ptr->owner_id);
|
||||
BLI_assert(adt != nullptr && adt->action == act);
|
||||
if (adt == nullptr || adt->action != act) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Ensure the id has an assigned slot. */
|
||||
Slot &slot = action.slot_ensure_for_id(*ptr->owner_id);
|
||||
action.assign_id(&slot, *ptr->owner_id);
|
||||
|
||||
action.layer_ensure_at_least_one();
|
||||
|
||||
assert_baklava_phase_1_invariants(action);
|
||||
KeyframeStrip &strip = action.layer(0)->strip(0)->as<KeyframeStrip>();
|
||||
|
||||
return &strip.fcurve_find_or_create(slot, fcurve_descriptor);
|
||||
}
|
||||
|
||||
/* Try to find f-curve matching for this setting.
|
||||
* - add if not found and allowed to add one
|
||||
|
||||
@@ -1074,7 +1074,8 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
/* create F-Curve for path animation */
|
||||
act = animrig::id_action_ensure(bmain, &cu->id);
|
||||
fcu = animrig::action_fcurve_ensure(bmain, act, nullptr, nullptr, {"eval_time", 0});
|
||||
PointerRNA id_ptr = RNA_id_pointer_create(&cu->id);
|
||||
fcu = animrig::action_fcurve_ensure(bmain, act, nullptr, &id_ptr, {"eval_time", 0});
|
||||
|
||||
/* standard vertical range - 1:1 = 100 frames */
|
||||
standardRange = 100.0f;
|
||||
@@ -1098,7 +1099,8 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op)
|
||||
|
||||
/* create F-Curve for constraint */
|
||||
act = animrig::id_action_ensure(bmain, &ob->id);
|
||||
fcu = animrig::action_fcurve_ensure(bmain, act, nullptr, nullptr, {path->c_str(), 0});
|
||||
PointerRNA id_ptr = RNA_id_pointer_create(&ob->id);
|
||||
fcu = animrig::action_fcurve_ensure(bmain, act, nullptr, &id_ptr, {path->c_str(), 0});
|
||||
|
||||
/* standard vertical range - 0.0 to 1.0 */
|
||||
standardRange = 1.0f;
|
||||
|
||||
@@ -544,8 +544,9 @@ bool parent_set(ReportList *reports,
|
||||
if (partype == PAR_FOLLOW) {
|
||||
/* get or create F-Curve */
|
||||
bAction *act = animrig::id_action_ensure(bmain, &cu->id);
|
||||
PointerRNA id_ptr = RNA_id_pointer_create(&cu->id);
|
||||
FCurve *fcu = animrig::action_fcurve_ensure(
|
||||
bmain, act, nullptr, nullptr, {"eval_time", 0});
|
||||
bmain, act, nullptr, &id_ptr, {"eval_time", 0});
|
||||
|
||||
/* setup dummy 'generator' modifier here to get 1-1 correspondence still working */
|
||||
if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first) {
|
||||
|
||||
Reference in New Issue
Block a user