[go: up one dir, main page]

Skip to content

Slotted Actions: Upgrading to 4.4

This page documents the upgrade path, from Blender 4.3 to 4.4, for Python code that was working with Actions and Action assignments.

For a basic overview of how to work with Slotted Actions, check Animation & Rigging and Python API in the 4.4 release notes.

Actions

This section describes the new API on the Action class

Getting the Action and Slot you want to work with

Blender 4.3 and older:

# Depending on the situation, get the Action from the animated thing.
action = animated_thing.animation_data.action

# Or use the action name:
action = bpy.data.actions["SuzanneAction"]

Blender 4.4:

# Depending on the situation, get the Action + Slot from the animated thing.
action = animated_thing.animation_data.action
slot = animated_thing.animation_data.action_slot

# Or use the action name and slot identifier:
action = bpy.data.actions["SuzanneAction"]
slot = action.slots["OBSuzanne"]

# Or create a new slot on an Action:
slot = action.slots.new(id_type='OBJECT', name="Suzanne")

Creating F-Curves and assigning Groups

Blender 4.3 and older:

fcurve = action.fcurves.new("location", index=1)
group = action.groups.new("Object Transform")
fcurve.group = group

Blender 4.4:

# If there is no yet a layer with a keyframe strip:
# (Blender 4.4 only supports a single layer with a single strip)
layer = action.layers.new("Layer")
strip = layer.strips.new(type='KEYFRAME')

# Or grab the existing one:
strip = action.layers[0].strips[0]

# Get the channelbag for this slot, creating it if necessary:
channelbag = strip.channelbag(slot, ensure=True)

# The channelbag behaves like legacy Actions:
fcurve = channelbag.fcurves.new("location", index=1)
group = channelbag.groups.new("Object Transform")
fcurve.group = group

Accessing existing F-Curves

Blender 4.3 and older:

fcurve = action.fcurves.find("location", index=1)
action.fcurves.remove(fcurve)

Blender 4.4:

# F-Curves can be found & removed from the appropriate channelbag.
strip = action.layers[0].strips[0]
channelbag = strip.channelbag(slot)

fcurve = channelbag.fcurves.find("location", index=1)
channelbag.fcurves.remove(fcurve)

Backward-Compatible Legacy API

The code shown above for "Blender 4.3 and older" will work in Blender 4.4 as well. The properties used there will act as a proxy for the data in action.layers[0].strips[0].channelbag(action.slots[0]), creating the layer, strip, and slot if necessary.

Similarly, action.id_root acts as a proxy for action.slots[0].target_id_type. Writing to action.id_root will write to action.slots[0].target_id_type, creating the slot if necessary.

Legacy API Are proxies of
action.fcurves action.layers[0].strips[0].channelbag(action.slots[0]).fcurves
action.groups action.layers[0].strips[0].channelbag(action.slots[0]).groups
action.id_root action.slots[0].target_id_type

This legacy API is considered deprecated, and will be removed in Blender 5.0.

Action & Slot Assignments

Technically, assigning Actions still works the same way:

object = bpy.context.object
anim_data = object.animation_data_create()
anim_data.action = action

In Blender 4.3, this was enough to make object animated by action.

In Blender 4.4, this assignment will try and auto-assign a slot as well, based on a set of heuristics. As a result, sometimes there may not be a slot auto-assigned, in which cases the Action assignment has worked, but does not result in the object actually being animated.

Assuming that a suitable slot exists on the Action, you can use this code to assign a slot explicitly:

# Assign the action as above, then:
anim_data.slot = anim_data.action_suitable_slots[0]

For more information, see AnimData in the Python API documentation.

NLA Strips & Action Constraints

NLA strips and Action Constraints have similar properties & behavior as the main Action & Slot assignment described above.

Just like normal Action assignment, assigning an Action will auto-assign a suitable slot as well. For NLA Strips and Action Constraints, this auto-assignment is a little bit more "eager" to select a slot: If there is a suitable slot on the Action (i.e. where its .target_id_type matches the animated data-block's .id_type), it will be chosen.

What did not change

Properties can still be keyed via the .keyframe_insert() method:

object = bpy.context.object
object.pose.bones["Arm_L"].keyframe_insert("rotation_euler", 1)

This will ensure the appropriate data exists, so:

  1. an action, and assign it to the object
  2. a slot for the object, and assign that too
  3. a layer, with a keyframe strip
  4. a channelbag for the slot
  5. the F-Curve, and where appropriate, a group for that F-Curve.