Monday, March 2, 2015

Action Management Roadmap - 2015 Version

In response to the concerns of users in the community (yes, we year you! Loud and clear :), I have ended up prioritizing looking into this, even at the expense of other even bigger issues that also need addressing.

Here is a quick overview of some of the efforts in motion now to address this matter.

1) The Situation
As is well known established by now, a lot of (predominantly but probably not exclusively) game animators are (very, very(?)) unhappy about the way that Action datablocks in Blender are managed following some changes during GSoc 2011 and released as part of 2.60, The change in question was that actions were no longer created with Fake Users by default. This was done for good reasons (outlined here), but repeated/rephrased again here:
  • The biggest reason at the time was that practically everyone was having trouble with large numbers of actions, many of these empty and devoid of any keyframes, accumulating in their files, and with no easy/clear ways to delete these.
  • Searching back through my email archives and also through the various forums reveals many examples of this becoming a significant production-bottleneck problem (especially when things like the nodetree compositor and its trigger-happy tendency to make copies of every datablock it touches to avoid threadsafety problems), as well as being a . Blend files were just bloating up and up and up (when RAM and internet speeds were still only slowly catching up), the removal process was arguably arcane (2.4x this revolve around Shift-F4 and file browser IIRC, and in 2.5 involved scrolling for ions in the "datablocks" view of the Outliner).
  • The original decision to give actions fake users by default was made back in ancient history of Blender, when their role was a lot different. Things have changed since then, with 2.5+ Actions being more like IPO blocks in <= 2.4x. Now, instead of just having a few actions for Pose animations (Note: on paper, they worked for Objects and Shapekeys, but Object support was clunky, and Shapekey support was extremely dodgy/buggy/unreliable - i.e. practically non-existent for all practical intents and purposes), they are now everywhere... from objects, to materials, lamps, textures, shapekey datablocks, nodetrees, world, scene, grease pencil, etc. etc. There are simply a hell of a lot more actions around these days - just like there were IPO's back in the day. IPO's didn't have Fake Users though (even though they were reusable like actions are).
1.1) The Changing Face of the NLA, and The Roles of "Action Libraries"
A secondary factor here for removing the fake users by default was that I was attempting to help bed in some workflow changes for how people go about working with the NLA and Actions. Previously, the NLA workflow was heavily tilted towards creating up libraries of actions, which were then added to the NLA stack (*1).

This action-library based approach to NLA usage is probably not that bad in and of itself (and indeed, can be useful for smaller studios to quickly block out TV pilots/storyboards quickly), except that between this and the confusing/ambiguous relationship between NLA and Actions, it gave rise to a peculiar workflow: Once they started using the NLA, animators have to create new "blank strips" - strips that were given new + empty actions, with the strips provisionally given a length of 100 (or was it 250 frames) - and would have to create these before they started animating in those cases.

The main issue with that NLA workflow though was that, between the automatic sync-strip-settings-on-every edit, and the code used to calculate how to scale and repeat the keyframes to reflect the strip's offsets, there would be destructive cycles where all the keyframes would get smooshed into a time range of 0.0001 frames (or something even more ridiculous) with a scale factor of 1 and lots of zeros! At one point, I was seeing a few new cases every other day!

That's why, the 2.5 design really pushed to focus on the "animation layering" view of using something like the NLA, versus raw "strip recombination". A less-clear focus on layering would almost certainly have lead to animators trying to carry over the damned "add then extend" mindset, with the assumption that the same old broken behaviours still exist. (*2)

In case you haven't see this post on how the relationship between the NLA stack and Actions is supposed to work, here's a quick summary of the "ground rules":
  • Each datablock which can be animated/driven has what's known as an "AnimData" (animation data) container. Inside this, there's the animation part, and the drivers part. These get evaluated separately - the animation first, then the drivers once all the other animation on things the drivers might depend on are ready.
  • The animation part has two components: the "Active Action" and the "NLA Stack". The meaning of these specific names is important for what we're about to see...
  • The "Active Action" slot is used to hold an action. This action is where keyframes are added when you insert keyframes, and is what the Dopesheet/Action Editor and Graph Editor will show you when you ask them to show you the keyframes of the action you're editing. The animation editors are effectively like "windows" looking at the "Active Action" slots.
  • The "Active Action" slot always sits "on top" of the NLA Stack. That is, once all the strips in the NLA stack which can be evaluated have been evaluated, only then does the Active Action get evaluated.
  • To allow editing the actions of strips, we have to temporarily make the strip in question sit in the active action slot. To do that, all tracks above this have to be disabled, to "roll back" the stack to the state when that action was first created. Thus, this action is known as "entering tweakmode"

  • (*1)  Back then, game animation and/or creating such assets using Blender - what with the lack of Unity, Steam, and all of that stuff - was still not really such a big thing yet, so "action libraries" - or bunches of actions just lying around unused in a .blend file - were mainly used for NLA usage only 
  • (*2) This also explains why, it wasn't until about a year ago that I finally started loosening the restrictions here, and started making it easier to set up NLA stacks from collections of pre-made actions. As a result of trying to diminish the role of premade action libraries being used, the importance of being able to have heaps of unused actions hanging around in a file really went down; if there are actions, they should be being used.

1.2) The Problems:
However, as a result of not setting fake users by default, users were starting to lose "action library" actions (i.e. orphaned/unused actions), as they were getting cleared away by Blender's "garbage-collection" mechanism for unused datablocks. This particular issue has been discussed to death already, so I will not elaborate further too much on this. Suffice to say - if a datablock had no users, Blender would not save that datablock's data, and the next time the file was loaded, the data would be gone. Technically-speaking, the key advantage of this approach was that it saves us from having issues where you might forcibly remove a datablock from the file, but because we somehow failed to pick up on the linkage, Blender will now segfault when it tries to access the now dead link. (The file reload step will nuke any such problems in the bud, as if there are any such dangling refs, they will not resolve - part of the deal with loading files is that you have to check every single link possible at that point - so we can easily defuse the situation there. Doing this on a live in-memory DB hooked up to tools and UI however is to play with fire).

The central thrust of the complaints is this: Apparently, the notion of taking the time to tell Blender about your intentions - that you do intend to keep a datablock around for later uses is in fact too error prone, even when that shading artists have had to be doing this when building up material libraries over the years with much less fanfare. IMO, it would seem rather obvious that if you're going to go to all that effort crafting something that you're going to be at least a bit paranoid/less-trusting that the computer will do something without being commanded to. (On this point, I should note that it's an important lesson to learn in general. For example, the auto backup/syncing things that Dropbox and co. do is IMO a disaster waiting to happen, and is why I stick to manual "push when I say push" systems, as you're only one dropped connected + scrambled/mistimed record sync away from having it think that the "without" state on the other end is the intended state, and it goes through and deletes your data).

Anyways, on this point, I now see that indeed, a more automated mechanism is needed to make these kinds of connections between actions and the things they were created for. Apart from this, there are other reasons that have convinced me that this is needed (but, it should be noted, strengthened why IMO Fake Users are absolutely not the answer - to suggest otherwise is silly). Namely, it seems that a large number of users have the notion that: "I created Action X for Object Y. Therefore, Blender should know that this action is related to the object I created it for!"... This mindset manifests in the following ways:
  1. Why are the actions I created earlier (and am keeping around using Fake Users) breaking when I rename the bones?
  2. Why does Blender "mix the actions for my tank and the turret"?   (This one comes from a recent thread on BA btw) 
  3. Argh! I just lost all the actions I spent all of yesterday working on!    (i.e. Most of the complaints)
The point is NOT that fake users are the magic antidote to this. (In fact, evidence is that they were directly responsible for masking a plethora of bugs, inconsistencies, and also preventing us from figuring out why some rigs would occasionally load up with missing actions or py constraints back in the 2.4x days when linking them into other files). The real point is that we need some mechanism for making Blender aware of the kind of links which users make, and which they assume the program also makes (but isn't)!

2) Workflows

2.1) Normal everyday "hero character" CA, or normal animation
Keyframes are inserted. Only a single action is used per datablock, per shot/scene.

2.2) Layered Character Animation
1. A rough animation pass is created for the character. This is "pushed down" onto the NLA Stack.
2. A second pass is then animated on top of the first. This is then "pushed down" onto the NLA Stack, on top of the first layer. The two layers now build up.
3. ... More layers are added like this ...
4. At any point, you can go back and edit a prior layer. To do so, you enter tweakmode on the layer in question, and we roll back the stack (i.e. disable all tracks above the action being tweaked) so that we're back to editing that layer only, as if it were the top of the stack again

2.3) Action Libraries/Game Animation
1. Create one walkcycle. Store it for later.
2. Create another walkcycle. Store it for later too.
3. ... Create more and more little cyclic animations ...
4. Switch between different actions previewing them
5. Switch back to a previous action, and start editing its keyframes to work better

3) Solutions
3.1) Action Libraries
A few years back, we got a patch to introduce "Action Libraries" for hanging on to the various actions created/being assigned to a datablock. At the time, implementation-wise, this patch required quite a few changes to be suitable for inclusion. It also mixed in some preview-range functionality too (more on this in a sec).

The idea here was that every time an action was created or assigned to that datablock, the Action Library on that datablock would take note of this, and keep an entry about this for later. Thus, now we would have the linkages that everyone expects, and Blender will not delete those Actions unless users specifically unlink them from these Action Libraries (thus making them unwanted orphans, which the garbage collection will gladly purge).

So, why hasn't this been included yet? Well, between feature freezes (to get the bug count down), other stuff that needed to be developed, a lack of time on my part to do much active dev at that point, it was clear that reviewing the patch would require a lot of careful reading of the code to make sure that each place it did stuff it didn't screw things up in subtle ways. I did recently start seriously chipping away at this, and have a local branch with some of this work in progress.

(*) Regarding the preview range additions, these were mainly around keeping the preview range synced with whatever action was active, so that editing these stored actions would be more fluent. However, the implementation here was a bit on the "too hacky" side, along with being mixed in with the rest of the patch.

(*) Now, regarding the version I've been working on - I plan to make this a datablock which can be linked into other files, making it easier to bring in a whole bunch of related actions into other files. This for instance would be useful when dealing with Pose Libraries - you could have one for facials, one for hands, and one for body, instead of having them all in one. There are still some issues to resolve with that idea though.

3.2) Stashing Actions in the NLA
In the meantime, the growing chorus for some change here was building momentum. It was clear that the action libraries plan could still take a while to settle, but something needed to be done in the interim.

This lead to the idea of taking advantage of the NLA instead in the interim. There are the following benefits of doing this:
  • Doing this immediately solves the problem of zero-user actions disappearing when users go to create new actions (and not knowing that creating a new action makes the other an orphan)
  • The NLA code for referencing and managing actions already exists, and is known to work already
  • If we can mark the track/strips where these actions are stashed as not contributing to the results of the NLA evaluation under normal circumstances, there is no harm done to storing these actions there. Normal contributing (i.e. non-muted) tracks can still be present without any problems.
  • Using the Solo toggle per track, it is possible to play only the action/strip in the track that had solo enabled on it. Thus, using this and a combination of tweakmode, you can go back and edit stashed actions. (A hotkey would help make this more effortless, but that can wait if necessary)
  • Storing these in the NLA provides a nice visual way of seeing what actions are stashed/linked, and they can be removed using all the usual means if they aren't wanted anymore
  • For game animators creating an action library - The NLA is going to be unused anyway. So, stashing all of these in there isn't going to hurt either way. In fact, it could probably be considered a win...
  • We also get to try out whether there are any other cases where we will be losing actions, and so any further "Action Libraries" work can address that better. Of particular relevance are the different ways that users may use for switching between actions or going between actions.
  • Any benefits we have from adding additional functionality here for tighter coherence between Action Editor and NLA would benefit others working in other workflows too (e.g. layered animation). Examples include adding a button to do "Push Down" from the Action Editor too, instead of having to keep/switch to NLA to do this. Other examples include stuff like more powerful switching between editors (Ctrl-Tab - Enter/Exit tweakmode and switch editor, Ctrl-Shift-Tab = Solo + Tweakmode + Switch Editor)
  • Future benefits - e.g. switching up/down between actions in NLA Tracks/layers, preview-range auto-adjusts on selecting actions, etc.
The downsides though are:
  • Increased clutter in the NLA from stashed actions getting included one-per-track at the bottom.
  • Sometimes the stashing may be unwanted, and will be a jack-in-the-box nuisance.
  • Cannot reuse the collection of stash actions easily (i.e. cannot just say "I want all those related to object X to be in my new file") 
  • This slightly subverts the original intentions of the NLA... Then again, if we're making good use of it for other things that it is well placed to serve, this is not that bad...

Here are some screenshots:
Two Actions already stashed; Working on a third...

Via the NLA - Going back over already-created actions (i.e. toggle solo on the relevant track) and checking them (i.e. entering tweakmode on the strip in question)

3.3) Orphaned Datablocks Mode in the Outliner
On a tangential front, I also set about making it easier to track down if some datablocks were going to get lost (and provide an easier way to catch and save these - as well as knock out any stubborn old fake-user-only datablocks). That's the point of the "Orphaned Datablocks" mode in the Outliner.

For more details about this, see the release notes on the wiki.

4) What's Done, and What's Coming Up Next?
Currently in master:
  • Creating new actions using the "New Action" button will stash the previously active action in the NLA stack before creating the new action. This means that you won't lose work that you're been working on.  (In the event that it does an "unwanted stash", the resolution is as simple as going into the NLA Editor, finding the offending/extra strip, and deleting it)
  • Added dedicated operator to push down actions to the NLA Stack (i.e. the action gets added to the stack as it would if you were doing this from the NLA Editor) from the Action Editor
  • Added dedicated operator to perform stashing operation (but without creating new action) beside the push down button
  • Various NLA tweaks to get this working nicer - Fixed some bugs with solo vs mute, it being hard to tell if a track was muted or not
  • Outliner "Orphaned Datablocks" mode  + Purge All operator there (which is just a shortcut to reload the file)
  • A bugfix for the Action Actuator to actually hang onto actions with a user like every other place now does
What's coming after the release (when we have more time):
  • Operators to switch between the editors when entering tweakmode
  • Operators in Action Editor to switch between the actions in the surrounding tracks (optionally solo, or with full stack included)
  • Preview range adapting to selected NLA strips automatically, and also when changing actions using the operators mentioned
  • Greater polish of the conditions under which actions get stashed automatically. Maybe we don't need to be as blindly-eager as we are now, and only add when it is likely there will be no user
  • Figure out ways to warn users when datablocks are close to being accidentally forgotten (i.e. on unliking with no other users, or if there are some orphans in the list file-wide)
  • A wider review across Blender or places where datablocks are used, and whether usercounts should be added. We don't seem to have any guidelines on when this is done/not done, and getting some solid ideas in place would be good.
Further down the track:
  • If it turns out that the Action Libraries (as datablocks) version is still really needed, we can start polishing that up, knowing better this time what exactly it'll need to cover for sure. Whether we keep using stash for this or whether we just move towards having this silently done is another matter.