[go: up one dir, main page]

Skip to content

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 and paint.eraser_brush are now read-only properties. (9e8c037375)

GPU

  • When drawing with POLYLINE_FLAT_COLOR, POLYLINE_SMOOTH_COLOR or POLYLINE_UNIFORM_COLOR or when drawing wide lines (line width greater than 1) using FLAT_COLOR, SMOOTH_COLOR or UNIFORM_COLOR, the following rules now apply:

    • The pos attribute must use F32 format FLOAT fetch type.
    • The color attribute must use F32 format with FLOAT fetch type or use U8 with 4 components and INT_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 or GPU_PRIM_LINE_LOOP.
    • If drawing using an index buffer, it must contain no primitive restart index.

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 to bpy.types.Strip. See the full list below.
  • Text strip align_x and align_y were renamed to anchor_x and anchor_y. Property alignment_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

Additions

bpy.app

  • Attribute bpy.app.portable indicates if Blender's installation is portable, matching the WITH_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.
  • Added a new property is_expanded to layer groups (e5bdfd533b). This returns True 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 and select_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