Action Baking to support animating on 2s

On 2021-03-09 there was a meeting in the Blender Animation Studio about improvements to the Action Baking system and to discuss the new pose library.

Present: Hjalti Hjálmarsson, Pablo Fournier, and Rik Schutte (animators), Sebastian Parborg and Sybren Stüvel (developers)

Preview Baking for Animating on 2s

The goal of the animators is to easily convert splined animation into stepped animation on 2s (i.e. keyed with constant interpolation every other frame) for previewing purposes. This means that a character’s Action should be converted to 2s, while maintaining other animation; most importantly, camera motion should remain smooth. This means that the “Viewport Render (a.k.a. Playblast) on Keys Only” feature in Blender is not suitable for this.

Suggested improvements for the Action Baking workflow to allow such preview baking:

  • When baking to a new Action, enable Fake User on the old Action. This ensures that the old action isn’t lost when saving the file.
  • Use a “keyframe holder” object/bone that defines which frames will be baked, by keying some arbitrary property.
  • Make sure that frames not baked have no keys. This is already covered by T82168: Improvements to “Bake Action…” Operator.
  • Allow setting a frame range. This is also included in T82168: Improvements to “Bake Action…” Operator.
  • On all baked keys, set the interpolation type to Constant.

Action Baking has also been discussed in 2021-02-18 Animation & Rigging Module Meeting.

Pose Library

Sybren gave a demonstration of the pose library prototype he’s been working on with Julian Eisel and Campbell Barton. It was received positively, with some ideas for improvements.

The current prototype simply copies animation data. This means a pose has to be keyed before it can be added to the pose library. This is not desired. Instead, the prototype will do this:

  • Always include the current location/rotation/scale/bbone properties of the selected bones.
  • If there are any other animated properties (not necessarily keyed on the current frame) on the selected bones, include their current value as well. This allows for inclusion of custom properties, for example for IK/FK switching, zipping a mouth, etc.
  • Allow for scripts (add-ons, scripted rigs) to provide a callback function. That function will receive the current context, and return a list of animation channels that should also be part of the pose. This should allow the rigger to include certain settings of the rig in a pose, even when these settings are not defined on any selected bone.
7 Likes

regarding that line i’d say 2 options either always return result in constant, or return result based on “default” key interpolation type set in the animation settings.

Regarding this, I agree, I would argue whenever a new datablock gets created ANYWHERE fake user should be ON by default and only be made off by user’s choice.

(could be a setting whether you want it like it is now or on by default)

super uber agree with everythig else :smiley:

I’m wondering what the advantage of this is over a modifier to add/remove “Stepped” fcurve-modifiers on demand.
This seems similar to a modifier I used on a project (on 2s) a while ago and the animators were able to non-destructively switch between interpolated and stepped as they wished. Baking is destructive and (to me) seems like the absolute wrong way to do this.
Of course you can also bake this with the current bake operator as-is.

From my point of view Blender already has all the tools needed for this; this is more of a pipeline/UI issue.

Here’s a simple operator that does the trick (for the active Object; can of course be changed to scene-wide etc.):

import bpy

class POSE_OT_FCurvesStepped(bpy.types.Operator):
    """Create Step Modifiers for all F-Curves"""
    bl_idname = 'pose.fcurves_stepped'
    bl_label = "Make Curves Stepped"
    bl_options = {'UNDO', 'REGISTER'}

    remove: bpy.props.BoolProperty(name="Remove Modifiers", default=False)
    frame_step: bpy.props.FloatProperty(name="Step Size", default=2.0)
    frame_offset: bpy.props.FloatProperty(name="Offset", default=0.0)

    @classmethod
    def poll(self, context):
        try:
            return context.active_object.animation_data.action
        except AttributeError:
            return None

    def execute(self, context):
        for fcurve in context.active_object.animation_data.action.fcurves:
            step = None
            for mod in fcurve.modifiers:
                if mod.type == 'STEPPED':
                    if self.remove:
                        fcurve.modifiers.remove(mod)
                    else:
                        step = mod
            if not step and not self.remove:
                step = fcurve.modifiers.new('STEPPED')
            if not self.remove:
                step.frame_step = self.frame_step
                step.frame_offset = self.frame_offset
        return {"FINISHED"}

def register():
    bpy.utils.register_class(POSE_OT_FCurvesStepped)

def unregister():
    bpy.utils.unregister_class(POSE_OT_FCurvesStepped)

if __name__ == "__main__":
    register()

In action:

Probably the best thing here is to adhere to Blender’s systems and stash the old action rather than fake user it - this keeps it associated with its character (so you can rename bones and have the action adapt)

It seems like being able to set a frame range in the operator would be nicer? Unless I’m missing a reason for this.

Overall question:
If the original animation isn’t on twos, why bake to twos? I imagine the animator has originally used the f-curve modifier or otherwise manually keyed the animation. Using baking seems like a too-blunt tool (often you’ll want to mix ones and twos and even threes in the same animation)

If the original animation isn’t on twos, why bake to twos?

This is for a specific style of animation where the initial animation will be made in spline for example (so no f-curve modifier), so every frame is ‘animated’. Then instead of baking animation on 2s, With the ‘keyframe holder’ the animator can decide which frames will be held on 2s and which frames will be on 1s. The ‘keyframe holder’ (this can be an arbitrary bone with keys on it) dictates the frames that are being baked. So this way the animator has more freedom to bake ‘inbetweens’ or ‘holds’ by keying the ‘keyframe holder’ accordingly. It will make the stepping more dynamic compared to a rigid ‘frame step’.

Yup @bkurdali, I was basically gonna write the same thing as @Rikstopher. By baking it based on they keys of a single bone, the animator can have the full flexibility of deciding which frames should be baked and which shouldn’t, so the can easily make a mix of 1’s 2’s 3’s etc.

You have a point with the “Stash” feature, I must admit that I’ve never actually used it before but now that I’ve explored the feature it seems like a good fit.

Ah I get it. Seems pretty cool as functionality, but putting this in baking seems like copying a feature without design first.
I would prefer to see this as a modifier (possibly NLA?) that can be used without baking first. Baking itself can be decoupled from that and would bake it just fine? Unless, for some reason, you’d like the baked keyframes to have the structure.

1 Like

I prefer to have this as a modifier over official baking as well - I’ve done a bunch of animation on twos and found that in general, the modifier method seems to work well. Once i’m down to final absolute finessing, I’ll bake things out… but only if I absolutely have to. Otherwise making large changes in animation can be quite difficult.