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.brush
andpaint.eraser_brush
are now read-only properties. (9e8c037375)
GPU¶
-
When drawing with
POLYLINE_FLAT_COLOR
,POLYLINE_SMOOTH_COLOR
orPOLYLINE_UNIFORM_COLOR
or when drawing wide lines (line width greater than 1) usingFLAT_COLOR
,SMOOTH_COLOR
orUNIFORM_COLOR
, the following rules now apply:- The
pos
attribute must useF32
formatFLOAT
fetch type. - The
color
attribute must useF32
format withFLOAT
fetch type or useU8
with 4 components andINT_TO_FLOAT_UNIT
for fetch mode. - Each attribute needs to be 4 byte aligned.
- Primitive type needs to be
GPU_PRIM_LINES
,GPU_PRIM_LINE_STRIP
orGPU_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.Sequence
and all related types were renamed tobpy.types.Strip
. See the full list below. - Text strip
align_x
andalign_y
were renamed toanchor_x
andanchor_y
. Propertyalignment_x
does 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.
Additions¶
bpy.app
¶
- Attribute
bpy.app.portable
indicates if Blender's installation is portable, matching theWITH_INSTALL_PORTABLE
build option. (481a8b67d4) - Attribute
bpy.app.module
indicates if Blender is running as a Python module. (a6b293daac)
Grease Pencil¶
- Added a setter for the
drawing
property 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_expanded
to layer groups (e5bdfd533b). This returnsTrue
if 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_tag
enum 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_tag
property, which returns an enum item corresponding to the node color tag (Texture, Vector, Output, etc...) (6cd33510c3) - New
bl_use_group_interface
property on custom node trees that allows disabling some built-in UI for node groups (ebfbc7757b).
Masks Points¶
- New
select_left_handle
,select_right_handle
,select_control_point
andselect_single_handle
properties (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 pyopenvdb
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
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 |