Fix #100718: NLA Hold Forward Inconsistency #109182
No reviewers
Labels
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset System
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Viewport & EEVEE
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Asset Browser Project
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Module
Viewport & EEVEE
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Severity
High
Severity
Low
Severity
Normal
Severity
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
5 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: blender/blender#109182
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "100718-NLA-hold-forward-inconsistency"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Finish landing the PR for 107281 in author's absence.
Problem:
For the Action Track, 'extrapolation=Hold Forward' behaves the same as
'Hold'. Animators expect 'Hold Forward' to behave consistently with the
rest of the NLA system but it does not.
Source of the problem:
Pre-patch, the problematic behavior was implemented as a special case
(see: animsys_create_action_track_strip() in anim_sys.c). It was added
added by commit
2826c2be54
. The fixeffectively removes the special handling while keeping the core intent
of the original commit, to have the Action Track evaluate fcurve
extrapolation properly.
Solution:
For the Action Track, we now properly treat extrapolation Hold_Forward
just like the rest of the NLA system (strips): as bounded on the left
and infinite on the right. In (anim_sys.c) nlastrips_ctime_get_strip(),
an additional boundary check is required since the original commit
assumed the only possible case, when NLASTRIP_FLAG_NO_TIME_MAP is
enabled, is effectively extrapolation=HOLD.
Quick Test File:
The cube is keyed at F50 and F70 with linear interpolation. The NLA has extrap=HoldForward.
Expect (PR): at frames before F50, the cube to be at world origin.
Expect (broken version): at frames before F50, the cube extrapolates towards the top left.
Approve from the animation/art side to have a working as shown NLA strip.
So, after some more testing, I'm starting to question whether this is really digging into the issue deeply enough.
When tweaking a strip (such that it ends up on the action track) everything already worked correctly even before this patch. So the issue is purely about what the desired behavior is for the directly-assigned action. Some thoughts:
Without other tracks/layered workflow it really doesn't matter what those settings are.
With other tracks, right now, the setting is correct, the display is correct, the result of both of those is wrong and what this fixes.
This is less about when we tweak an action than it is about when we are creating new actions in a LAYERED workflow situation...vs using the NLA for other reasons.
"If we resolve that inconsistency by making the hold behavior have an effect even without any NLA tracks, then there's no way to get the current (and IMO desirable behavior) where the action is still evaluated before and after the first/last key frames, which matters when there's extrapolation or modifiers on the f-curves."
HOLD would work and does, it is hold FORWARD that is the issue, in that it does NOT only hold forward, it still acts as HOLD...
Talked with @BClark at the animation workshop about this, and it turns out I was misunderstanding the situation. So please disregard my concerns in my last comment.
For reference: the crux of my misunderstanding was that the different hold behavior of the action track when there are no NLA tracks isn't because the action track is treated as special, but is rather because the base track is, and adding NLA tracks simply makes the action track no longer the base track. This is necessary because the base track has no tracks underneath it to blend with, and the animation values have to be set to something.
I can confirm the code works!
@nathanvegdahl helped me a bit. The trick is that to see the behaviour, you also need a regular NLA track, and not just the action track.
As a final thought, we should think about versioning code as well. If Hold Forward is going to change behaviour, we might want to version files so that they still behave the same after loading into 4.0. It might be enough to set the extrapolation to 'Hold' whenever it was set to 'Hold Forward', as that would match how 3.6 behaved?
As a followup PR, I think it would be good to have this section of the NLA properties panel deactivated (so greyed out but still editable) whenever there are no NLA tracks.
Only if it's simple to do though. I'd rather see us put effort into the new model, rather than polishing the NLA. Fixes like in this PR are still good, as they actually hamper people in their workflow.
@ -631,2 +631,3 @@
for (; fcurve_offset < 4 && quat_curve_fcu;
++fcurve_offset, quat_curve_fcu = quat_curve_fcu->next) {
++fcurve_offset, quat_curve_fcu = quat_curve_fcu->next)
{
Please keep formatting changes out of the patch.
@ -3252,0 +3266,4 @@
/* Must set NLASTRIP_FLAG_USR_INFLUENCE, or else the default setting overrides, and influence
* doesn't work.
*
* Must set NLASTRIP_FLAG_NO_TIME_MAP, so Action Track fcurve evaluation extends beyond its
This is a bit confusing. The comment says that
NLASTRIP_FLAG_NO_TIME_MAP
must be set, but the code here doesn't set it.Originally posted by @BClark in #107281:
If I'm right with my above comment on versioning, in that we can keep the behaviour of files exactly the same, then I think this can go into 3.6.1. If not, then we have to do a more careful analysis.
Just a note:
" I think it would be good to have this section of the NLA properties panel deactivated (so greyed out but still editable) whenever there are no NLA tracks."
This seems like at first glance it is a good idea but with the con of removing the ability to preset how the animation works when the clip is created/pushed the first time vs. not being able to change them until after creating a strip.
I don't think you got the "but still editable" part of what I wrote. Blender has both "inactive" and "disabled" states. They both appear greyed-out, but the "inactive" state still allows changing the parameters.
@blender-bot package
Package build started. Download here when ready.
Just took another look at the code, and this looks ready to land to me. If I understand the conversation above, we want to target this for both the 3.6 LTS branch and 4.0.
@dr.sybren When you get back from vacation, can you confirm? And then we can get this landed.
Almost there!
@ -1053,0 +1062,4 @@
continue;
}
if (&adt->nla_tracks != nullptr && adt->action != nullptr) {
Style wise, I think this condition can be merged with the one above. Or at least flipped and using
continue
.Also how is
&adt->nla_tracks
ever going to benullptr
? That would only happen whenadt = -offsetof(AnimData, nla_tracks)
, which is rather unlikely. I think what you're looking for isBLI_listbase_is_empty(&adt->nla_tracks)
.And finally, what's the
adt->action
check for? Is it really important that this versioning doesn't happen when the NLA is active and an Action has been assigned? If it is, might be worth a comment that explains why.The hold forward issue only occurs when there is an action and at least one NLA track. Thus, to preserve backwards functionality, yes we need to check for this. Will add a comment 👍
@ -1053,0 +1067,4 @@
LISTBASE_FOREACH (NlaTrack *, track, &adt->nla_tracks) {
if(BLI_listbase_count(&track->strips) > 0){
has_nla_strip = true;
Since
has_nla_strip
is never set tofalse
, you canbreak
here. Also I feel this could be a separate function likeBKE_animdata_has_nla(AnimData *adt)
orBKE_nla_is_active(ID *id)
or something along those lines (I'm not a fan of the "is active" as "active" in Blender is such a specific term, but can't think of a better name right now).@ -1053,0 +1071,4 @@
}
}
/* Only update action extend mode if there's a strip present. */
if (adt->act_extendmode == NLASTRIP_EXTEND_HOLD_FORWARD && has_nla_strip) {
adt->act_extendmode == NLASTRIP_EXTEND_HOLD_FORWARD
does not depend on the NLA strip being present or not. Just addif (adt->act_extendmode != NLASTRIP_EXTEND_HOLD_FORWARD) continue;
to the precondition checks at the top.@ -1055,0 +1061,4 @@
FOREACH_MAIN_ID_BEGIN (bmain, id) {
AnimData *adt = BKE_animdata_from_id(id);
/* We only want to preserve existing behavior if there's an action and 1 or more NLA strips. */
if (adt == nullptr || BLI_listbase_is_empty(&adt->nla_tracks) || adt->action == nullptr ||
Shouldn't this be using
BKE_nlatrack_has_strips(&adt->nla_tracks)
instead ofBLI_listbase_is_empty()
? The comments says to check for existence of strips, but the code checks for existence of tracks. Given that you callBKE_nlatrack_has_strips
below anyway, I think you can remove the call toBLI_listbase_is_empty()
here and keep the condition a bit simpler.Thanks!