Blender 4.4: Python API¶
Breaking Changes¶
Subclassing Blender Types¶
Python-defined classes based on Blender types (like Operator, PropertyGroup, etc.)
that define their own __new__/__init__ constructors must now call the parent's matching
function,
and pass on generic positional and keyword arguments:
import bpy
class AwesomeRaytracer(bpy.types.RenderEngine):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
...
Paint¶
paint.brushis now a read-only property. (9e8c037375)brush.clone_image,brush.clone_alpha, andbrush.clone_offsetare removed. (f1fca48a4f)- Painting operators'
strokeparameter no longer takes in thepen_flipproperty on a per-element basis. (6df437be5f)
GPU¶
-
When drawing with
POLYLINE_FLAT_COLOR,POLYLINE_SMOOTH_COLORorPOLYLINE_UNIFORM_COLORor when drawing wide lines (line width greater than 1) usingFLAT_COLOR,SMOOTH_COLORorUNIFORM_COLOR, the following rules now apply:- The
posattribute must useF32formatFLOATfetch type. - The
colorattribute must useF32format withFLOATfetch type or useU8with 4 components andINT_TO_FLOAT_UNITfor fetch mode. - Each attribute needs to be 4 byte aligned.
- Primitive type needs to be
GPU_PRIM_LINES,GPU_PRIM_LINE_STRIPorGPU_PRIM_LINE_LOOP. - If drawing using an index buffer, it must contain no primitive restart index.
- The
Grease Pencil¶
- The influence vertex group was removed from the Texture Mapping modifier (c452d5d9e8)
Video Sequencer¶
- The
bpy.types.Sequenceand all related types were renamed tobpy.types.Strip. See the full list below. - Text strip
align_xandalign_ywere renamed toanchor_xandanchor_y. Propertyalignment_xdoes proper alignment now. (77a5478c0f)
User Interface¶
UILayout.template_icon()displays built-in icons in a normal size, not scaled up to fit the button. (1f88645728)
Actions¶
- Actions now have Slots, which requires changes to action assignment and editing. See the detailed explanation below for how to update.
Compositor¶
- Removed
PreferencesExperimental.enable_new_cpu_compositorandRenderSettings.use_new_cpu_compositor(the new CPU compositor is always used now). (PR#131783)
Additions¶
bpy.app¶
- Attribute
bpy.app.portableindicates if Blender's installation is portable, matching theWITH_INSTALL_PORTABLEbuild option. (481a8b67d4) - Attribute
bpy.app.moduleindicates if Blender is running as a Python module. (a6b293daac)
Grease Pencil¶
- Added a setter for the
drawingproperty on frame python API (dc6e879d0f).- Can be used to copy a drawing from elsewhere (e.g. another layer or object):
frame.drawing = other_drawing.
- Can be used to copy a drawing from elsewhere (e.g. another layer or object):
- Added a new property
is_expandedto layer groups (e5bdfd533b). This returnsTrueif the layer group is expanded in the layer tree UI. - Added a function to reorder strokes in a drawing:
drawing.reorder_strokes(new_indices=[...])(a265b591be). - Added a
color_tagenum property to layer groups that exposes the color tag (36d69e8491). - The influence vertex group was removed from the Texture Mapping modifier (c452d5d9e8)
Curves¶
- New
Curves.reorder_curves(new_indices=[...])to reorder curves. (a265b591be) - New
Curves.set_types()to change curve types (5db88ff2e3).
Nodes¶
- New
Node.color_tagproperty, which returns an enum item corresponding to the node color tag (Texture, Vector, Output, etc...) (6cd33510c3) - New
bl_use_group_interfaceproperty on custom node trees that allows disabling some built-in UI for node groups (ebfbc7757b). - Removed
scene.tool_settings.snap_node_element. Whenscene.tool_settings.snap_node = Trueis set, nodes are snapped to grid (35ea495bb6).
Masks Points¶
- New
select_left_handle,select_right_handle,select_control_pointandselect_single_handleproperties (462d887114)
Blender as a Python Module¶
The bpy package on PyPI now provides access to VFX libraries used by Blender.
(PR#133082)
While most are available as separate packages on PyPI, they may not have the same version or build options as Blender. This can lead to errors when interchanging data with Blender, which are resolved by using the matching version.
import bpy
# Add Blender bundled VFX libraries to sys.path.
bpy.utils.expose_bundled_modules()
# Import the library you need.
import pxr
import MaterialX
import OpenImageIO
import PyOpenColorIO
import openvdb
Note that as of Blender 4.4, the pyopenvdb module name is no longer available.
It has been replaced by openvdb in both the bpy package and Blender itself.
Slotted Actions¶
Breaking¶
Assigning an Action (datablock.animation_data.action = some_action) may, under certain conditions,
not auto-assign an action slot, hence leave the data-block in a non-animated state. To force
assignment of the first slot of the action, follow up the assignment with
datablock.animation_data.action_slot = some_action.slots[0]. This assumes that the first slot's
target_id_type is either UNSPECIFIED or the same as datablock.id_type. This assumption holds
for just-versioned Actions.
Note
Assigning Actions to an NLA strip or an Action constraint works slightly differently.
Setting strip.action = some_action or constraint.action = some_action will always auto-assign
the first slot that has a compatible target_id_type (docs). As such, this is
actually backward-compatible as the state after the assignment is the same (the Action animates
the thing).
Additions¶
Slotted Actions are part of an ongoing endeavour to make Actions fully layered. Even though layering is not supported yet, the data model is ready for layers and strips. This is reflected in the new API for slotted Actions.
import bpy
# Actions are created as before.
action = bpy.data.actions.new("SuzanneAction")
# Creation of slots requires an ID type and a name.
slot = action.slots.new(id_type='OBJECT', name="Suzanne")
print(f"slot type={slot.target_id_type} name={slot.name_display} identifier={slot.identifier}")
# Output:
# slot type=OBJECT name=Suzanne identifier=OBSuzanne
# F-Curves and Channel Groups are now stored on an infinite keyframe strip that sits on a layer.
layer = action.layers.new("Layer")
strip = layer.strips.new(type='KEYFRAME')
channelbag = strip.channelbag(slot, ensure=True)
# F-Curves and Groups are created on the channelbag with the same API as previously on `action`.
# F-Curves and Groups themselves also still have exactly the same API as before.
fcurve = channelbag.fcurves.new("location", index=1)
group = channelbag.groups.new("Object Transform")
fcurve.group = group
# Assigning the Action will automatically select the slot, as it matches Suzanne's ID type + name:
suzanne = bpy.data.objects["Suzanne"]
anim_data = suzanne.animation_data_create()
anim_data.action = action
# If explicit slot assignment is needed:
anim_data.action_slot = action.slots[0]
# If there are multiple slots on the Action, and you want to just pick the first one that's
# compatible, use the following code. `anim_data.action_suitable_slots` can be used _after_ the
# Action has been assigned; it is a list of action slots of that Action, but only the ones that
# are actually compatible with the owner of anim_data (in this case, Suzanne).
anim_data.action_slot = anim_data.action_suitable_slots[0]
# Alternatively, you can set the 'last-used slot identifier' to determine which slot is auto-assigned:
anim_data.last_slot_identifier = 'OBDancing Monkey'
anim_data.action = action
print(anim_data.action_slot.identifier)
# Output: OBDancing Monkey, if that slot exists on the Action
# Get the data-blocks that are animated by a certain slot:
for action in bpy.data.actions:
print(f"Action: {action.name}")
for slot in action.slots:
print(f" slot {slot.identifier} is ", end="")
slot_users = slot.users()
if not slot_users:
print("unused")
continue
print("used by:")
for datablock in slot_users:
print(f" - {datablock!r}")
The above code shows the low-level functionality. If all you need is to ensure an F-Curve exists on the Action, in order to animate a specific data-block, you can use a convenience function for this:
import bpy
# Actions are created as before:
action = bpy.data.actions.new("SuzanneAction")
# Assign the Action so that Blender knows about the relationship with Suzanne:
suzanne = bpy.data.objects["Suzanne"]
suzanne.animation_data_create().action = action
# Create the F-Curves:
loc_x = action.fcurve_ensure_for_datablock(suzanne, "location", index=0)
loc_y = action.fcurve_ensure_for_datablock(suzanne, "location", index=1)
loc_z = action.fcurve_ensure_for_datablock(suzanne, "location", index=2)
If you just want to find the channelbag for a specific slot, there's a convenience function for that as well. This function assumes that the Action only has at most one layer, and at most one keyframe strip. This assumption holds for all Actions in Blender 4.4. Calling this function is a good indicator that the code will need some attention when multi-layered animation is added in the future.
import bpy
from bpy_extras import anim_utils
# Suzanne is assumed to already be animated:
suzanne = bpy.data.objects["Suzanne"]
action = suzanne.animation_data.action
action_slot = suzanne.animation_data.action_slot
channelbag = anim_utils.action_get_channelbag_for_slot(action, action_slot)
# Now you can access the F-Curves in the channelbag:
for fcurve in channelbag.fcurves:
print(f"FCurve: {fcurve.data_path}[{fcurve.array_index}]")
The code below, which worked on older versions of Blender as well, still works in 4.4:
import bpy
# Just get the object, and start inserting keys. This will create
# the Action, with a layer, keyframe strip, channelbag, slot, and
# assign the Action and the slot to Suzanne.
suzanne = bpy.data.objects["Suzanne"]
suzanne.keyframe_insert("location", index=0)
suzanne.keyframe_insert("location", index=1)
suzanne.keyframe_insert("location", index=2)
Note
Even though the data model is ready for having multiple layers, and multiple strips per layer, Blender is currently limited to only a single layer with a single keyframe strip. The strip is infinitely long, and cannot be moved.
Deprecated¶
These legacy function / attributes of the Action type have been marked as 'backward-compatible
legacy API'. They all operate on the data for the first action slot only, and create the necessary
data structures where needed.
| Legacy API | Modern API |
|---|---|
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 will be removed in Blender 5.0
Video Sequencer Strips¶
Breaking¶
The type bpy.types.Sequence has been renamed to bpy.types.Strip together will all related types. (d3ba70190b)
Here is the full list:
4.3 |
4.4 |
|---|---|
bpy.types.Sequence |
bpy.types.Strip |
bpy.types.EffectSequence |
bpy.types.EffectStrip |
bpy.types.AddSequence |
bpy.types.AddStrip |
bpy.types.AdjustmentSequence |
bpy.types.AdjustmentStrip |
bpy.types.AlphaOverSequence |
bpy.types.AlphaOverStrip |
bpy.types.AlphaUnderSequence |
bpy.types.AlphaUnderStrip |
bpy.types.ColorMixSequence |
bpy.types.ColorMixStrip |
bpy.types.ColorSequence |
bpy.types.ColorStrip |
bpy.types.CrossSequence |
bpy.types.CrossStrip |
bpy.types.GammaCrossSequence |
bpy.types.GammaCrossStrip |
bpy.types.GaussianBlurSequence |
bpy.types.GaussianBlurStrip |
bpy.types.GlowSequence |
bpy.types.GlowStrip |
bpy.types.MulticamSequence |
bpy.types.MulticamStrip |
bpy.types.MultiplySequence |
bpy.types.MultiplyStrip |
bpy.types.OverDropSequence |
bpy.types.OverDropStrip |
bpy.types.SpeedControlSequence |
bpy.types.SpeedControlStrip |
bpy.types.SubtractSequence |
bpy.types.SubtractStrip |
bpy.types.TextSequence |
bpy.types.TextStrip |
bpy.types.TransformSequence |
bpy.types.TransformStrip |
bpy.types.WipeSequence |
bpy.types.WipeStrip |
bpy.types.ImageSequence |
bpy.types.ImageStrip |
bpy.types.MaskSequence |
bpy.types.MaskStrip |
bpy.types.MetaSequence |
bpy.types.MetaStrip |
bpy.types.MovieClipSequence |
bpy.types.MovieClipStrip |
bpy.types.MovieSequence |
bpy.types.MovieStrip |
bpy.types.SceneSequence |
bpy.types.SceneStrip |
bpy.types.SoundSequence |
bpy.types.SoundStrip |
bpy.types.SequenceColorBalanceData |
bpy.types.StripColorBalanceData |
bpy.types.SequenceColorBalance |
bpy.types.StripColorBalance |
bpy.types.SequenceCrop |
bpy.types.StripCrop |
bpy.types.SequenceElement |
bpy.types.StripElement |
bpy.types.SequenceElements |
bpy.types.StripElements |
bpy.types.SequenceModifier |
bpy.types.StripModifier |
bpy.types.SequenceModifiers |
bpy.types.StripModifiers |
bpy.types.SequenceProxy |
bpy.types.StripProxy |
bpy.types.SequenceTransform |
bpy.types.StripTransform |
bpy.types.SequencesMeta |
bpy.types.StripsMeta |
bpy.types.SequencesTopLevel |
bpy.types.StripsTopLevel |
Deprecated¶
Properties that refer to a bpy.types.Strip (previously bpy.types.Sequence) as "sequence" have been deprecated. New properties with "strip" are added. The old properties remain available until 5.0 but addon developers are encouraged to update their addons to use the new property names:
| Deprecated property | New property |
|---|---|
context.active_sequence_strip |
context.active_strip |
context.selected_editable_sequences |
context.selected_editable_strips |
context.selected_sequences |
context.selected_strips |
context.sequences |
context.strips |
SequenceEditor.sequences |
SequenceEditor.strips |
SequenceEditor.sequences_all |
SequenceEditor.strips_all |
MetaStrip.sequences |
MetaStrip.strips |