Blender Python API Reference¶
Quick reference guide for Blender's Python API (bpy) commonly used with BlenderForge.
Table of Contents¶
- Overview
- Core Modules
- Scene and Objects
- Mesh Operations
- Materials and Textures
- Modifiers
- Animation
- Rendering
- Common Patterns
- BlenderForge Integration
- Resources
Overview¶
Blender's Python API (bpy) provides programmatic access to almost all of Blender's functionality. BlenderForge uses this API to execute commands sent from AI assistants.
Importing bpy¶
Key Concepts¶
| Concept | Description | Access |
|---|---|---|
| Context | Current state (selection, mode, etc.) | bpy.context |
| Data | All Blender data blocks | bpy.data |
| Operators | Actions/commands | bpy.ops |
| Types | Blender type definitions | bpy.types |
| Props | Custom properties | bpy.props |
Core Modules¶
bpy.context - Current State¶
# Active objects and selections
bpy.context.scene # Current scene
bpy.context.object # Active object
bpy.context.selected_objects # List of selected objects
bpy.context.view_layer # Active view layer
bpy.context.mode # Current mode ('OBJECT', 'EDIT', etc.)
# Examples
scene_name = bpy.context.scene.name
active_obj = bpy.context.object
selected = bpy.context.selected_objects
bpy.data - Data Blocks¶
# Access all data of a type
bpy.data.objects # All objects
bpy.data.meshes # All meshes
bpy.data.materials # All materials
bpy.data.textures # All textures
bpy.data.images # All images
bpy.data.scenes # All scenes
bpy.data.collections # All collections
bpy.data.armatures # All armatures
bpy.data.cameras # All cameras
bpy.data.lights # All lights
# Access by name
cube = bpy.data.objects['Cube']
mat = bpy.data.materials['Material']
bpy.ops - Operators¶
# Mesh primitives
bpy.ops.mesh.primitive_cube_add()
bpy.ops.mesh.primitive_uv_sphere_add()
bpy.ops.mesh.primitive_cylinder_add()
bpy.ops.mesh.primitive_plane_add()
# Object operations
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
bpy.ops.object.duplicate()
# Transform
bpy.ops.transform.translate()
bpy.ops.transform.rotate()
bpy.ops.transform.resize()
Scene and Objects¶
Creating Objects¶
# Add primitives at specific locations
bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0))
bpy.ops.mesh.primitive_uv_sphere_add(radius=1, location=(2, 0, 0))
bpy.ops.mesh.primitive_cylinder_add(radius=0.5, depth=2, location=(4, 0, 0))
bpy.ops.mesh.primitive_plane_add(size=10, location=(0, 0, -1))
bpy.ops.mesh.primitive_cone_add(radius1=1, depth=2, location=(6, 0, 0))
bpy.ops.mesh.primitive_torus_add(major_radius=1, minor_radius=0.25)
# Monkey (Suzanne)
bpy.ops.mesh.primitive_monkey_add(location=(0, 0, 2))
# Empty
bpy.ops.object.empty_add(type='PLAIN_AXES', location=(0, 0, 0))
# Camera
bpy.ops.object.camera_add(location=(0, -5, 2))
# Light
bpy.ops.object.light_add(type='POINT', location=(0, 0, 5))
bpy.ops.object.light_add(type='SUN', location=(0, 0, 10))
bpy.ops.object.light_add(type='AREA', location=(0, 0, 3))
Accessing Objects¶
# Get object by name
obj = bpy.data.objects.get('Cube')
# Check if object exists
if 'Cube' in bpy.data.objects:
cube = bpy.data.objects['Cube']
# Get active object
active = bpy.context.object
# Get selected objects
selected = bpy.context.selected_objects
for obj in selected:
print(obj.name)
Object Properties¶
obj = bpy.data.objects['Cube']
# Transform
obj.location = (1, 2, 3)
obj.rotation_euler = (0, 0, 0.785) # Radians (45 degrees)
obj.scale = (2, 2, 2)
# Read transform
pos = obj.location
rot = obj.rotation_euler
scl = obj.scale
# Dimensions (bounding box)
dims = obj.dimensions
# Type
obj_type = obj.type # 'MESH', 'CAMERA', 'LIGHT', etc.
# Visibility
obj.hide_viewport = False
obj.hide_render = False
Object Selection¶
import bpy
# Deselect all
bpy.ops.object.select_all(action='DESELECT')
# Select by name
obj = bpy.data.objects['Cube']
obj.select_set(True)
# Make active
bpy.context.view_layer.objects.active = obj
# Select all
bpy.ops.object.select_all(action='SELECT')
# Select by type
for obj in bpy.data.objects:
if obj.type == 'MESH':
obj.select_set(True)
Deleting Objects¶
# Delete selected objects
bpy.ops.object.delete()
# Delete specific object
obj = bpy.data.objects.get('Cube')
if obj:
bpy.data.objects.remove(obj)
# Delete all mesh objects
for obj in bpy.data.objects:
if obj.type == 'MESH':
bpy.data.objects.remove(obj)
Mesh Operations¶
Creating Mesh from Scratch¶
import bpy
import bmesh
# Create mesh data
mesh = bpy.data.meshes.new('CustomMesh')
# Create vertices and faces
vertices = [
(-1, -1, 0),
(1, -1, 0),
(1, 1, 0),
(-1, 1, 0),
]
edges = []
faces = [(0, 1, 2, 3)]
# Apply to mesh
mesh.from_pydata(vertices, edges, faces)
mesh.update()
# Create object from mesh
obj = bpy.data.objects.new('CustomObject', mesh)
# Link to scene
bpy.context.collection.objects.link(obj)
BMesh Operations¶
import bpy
import bmesh
# Get active object's mesh
obj = bpy.context.object
bm = bmesh.new()
bm.from_mesh(obj.data)
# Create a vertex
v = bm.verts.new((0, 0, 1))
# Update indices
bm.verts.ensure_lookup_table()
# Apply to mesh
bm.to_mesh(obj.data)
bm.free()
Edit Mode Operations¶
import bpy
# Enter edit mode
bpy.ops.object.mode_set(mode='EDIT')
# Select all vertices
bpy.ops.mesh.select_all(action='SELECT')
# Extrude
bpy.ops.mesh.extrude_region_move(
TRANSFORM_OT_translate={"value": (0, 0, 1)}
)
# Subdivide
bpy.ops.mesh.subdivide(number_cuts=2)
# Return to object mode
bpy.ops.object.mode_set(mode='OBJECT')
Materials and Textures¶
Creating Materials¶
import bpy
# Create new material
mat = bpy.data.materials.new(name="MyMaterial")
mat.use_nodes = True
# Access node tree
nodes = mat.node_tree.nodes
links = mat.node_tree.links
# Get Principled BSDF node
bsdf = nodes.get('Principled BSDF')
# Set base color (RGBA)
bsdf.inputs['Base Color'].default_value = (1, 0, 0, 1) # Red
# Set other properties
bsdf.inputs['Metallic'].default_value = 0.5
bsdf.inputs['Roughness'].default_value = 0.3
bsdf.inputs['Alpha'].default_value = 1.0
Assigning Materials¶
import bpy
# Get object and material
obj = bpy.data.objects['Cube']
mat = bpy.data.materials['MyMaterial']
# Assign to object
if obj.data.materials:
obj.data.materials[0] = mat # Replace first slot
else:
obj.data.materials.append(mat) # Add new slot
Creating PBR Material with Nodes¶
import bpy
def create_pbr_material(name, color, metallic=0.0, roughness=0.5):
"""Create a PBR material with the given properties."""
mat = bpy.data.materials.new(name=name)
mat.use_nodes = True
nodes = mat.node_tree.nodes
links = mat.node_tree.links
# Clear existing nodes
nodes.clear()
# Add output node
output = nodes.new('ShaderNodeOutputMaterial')
output.location = (300, 0)
# Add Principled BSDF
bsdf = nodes.new('ShaderNodeBsdfPrincipled')
bsdf.location = (0, 0)
bsdf.inputs['Base Color'].default_value = (*color, 1.0)
bsdf.inputs['Metallic'].default_value = metallic
bsdf.inputs['Roughness'].default_value = roughness
# Connect
links.new(bsdf.outputs['BSDF'], output.inputs['Surface'])
return mat
# Usage
mat = create_pbr_material("Gold", (1, 0.8, 0), metallic=1.0, roughness=0.2)
Loading Images as Textures¶
import bpy
# Load image
img = bpy.data.images.load('/path/to/texture.png')
# Create material with image texture
mat = bpy.data.materials.new(name="TexturedMaterial")
mat.use_nodes = True
nodes = mat.node_tree.nodes
links = mat.node_tree.links
# Add image texture node
tex_node = nodes.new('ShaderNodeTexImage')
tex_node.image = img
tex_node.location = (-300, 0)
# Connect to Principled BSDF
bsdf = nodes.get('Principled BSDF')
links.new(tex_node.outputs['Color'], bsdf.inputs['Base Color'])
Modifiers¶
Adding Modifiers¶
import bpy
obj = bpy.context.object
# Subdivision Surface
subsurf = obj.modifiers.new(name="Subsurf", type='SUBSURF')
subsurf.levels = 2
subsurf.render_levels = 3
# Mirror
mirror = obj.modifiers.new(name="Mirror", type='MIRROR')
mirror.use_axis[0] = True # X axis
# Array
array = obj.modifiers.new(name="Array", type='ARRAY')
array.count = 5
array.relative_offset_displace = (1.5, 0, 0)
# Boolean
boolean = obj.modifiers.new(name="Boolean", type='BOOLEAN')
boolean.operation = 'DIFFERENCE'
boolean.object = bpy.data.objects['Cutter']
# Bevel
bevel = obj.modifiers.new(name="Bevel", type='BEVEL')
bevel.width = 0.02
bevel.segments = 3
Applying Modifiers¶
import bpy
obj = bpy.context.object
# Apply all modifiers
for mod in obj.modifiers:
bpy.ops.object.modifier_apply(modifier=mod.name)
# Apply specific modifier
bpy.ops.object.modifier_apply(modifier="Subsurf")
Animation¶
Setting Keyframes¶
import bpy
obj = bpy.data.objects['Cube']
# Set location at frame 1
bpy.context.scene.frame_set(1)
obj.location = (0, 0, 0)
obj.keyframe_insert(data_path="location", frame=1)
# Set location at frame 50
bpy.context.scene.frame_set(50)
obj.location = (5, 0, 0)
obj.keyframe_insert(data_path="location", frame=50)
# Other properties
obj.keyframe_insert(data_path="rotation_euler", frame=1)
obj.keyframe_insert(data_path="scale", frame=1)
Creating Simple Animation¶
import bpy
import math
obj = bpy.data.objects['Cube']
# Clear existing animation
obj.animation_data_clear()
# Create bouncing animation
for frame in range(1, 101):
bpy.context.scene.frame_set(frame)
# Calculate bounce
t = frame / 100
height = abs(math.sin(t * math.pi * 4)) * 2
obj.location.z = height
obj.keyframe_insert(data_path="location", index=2, frame=frame)
Armature Animation¶
import bpy
armature = bpy.data.objects['Armature']
bpy.context.view_layer.objects.active = armature
bpy.ops.object.mode_set(mode='POSE')
bone = armature.pose.bones['Bone']
# Set keyframes
bpy.context.scene.frame_set(1)
bone.rotation_quaternion = (1, 0, 0, 0)
bone.keyframe_insert(data_path="rotation_quaternion", frame=1)
bpy.context.scene.frame_set(30)
bone.rotation_quaternion = (0.707, 0.707, 0, 0)
bone.keyframe_insert(data_path="rotation_quaternion", frame=30)
bpy.ops.object.mode_set(mode='OBJECT')
Rendering¶
Render Settings¶
import bpy
scene = bpy.context.scene
# Resolution
scene.render.resolution_x = 1920
scene.render.resolution_y = 1080
scene.render.resolution_percentage = 100
# Output format
scene.render.image_settings.file_format = 'PNG'
scene.render.filepath = '/path/to/output.png'
# Render engine
scene.render.engine = 'CYCLES' # or 'BLENDER_EEVEE'
# Samples (Cycles)
scene.cycles.samples = 128
scene.cycles.preview_samples = 32
# Samples (EEVEE)
scene.eevee.taa_render_samples = 64
Executing Render¶
import bpy
# Render current frame
bpy.ops.render.render(write_still=True)
# Render animation
bpy.ops.render.render(animation=True)
# Render to viewport (for screenshots)
bpy.ops.render.opengl(write_still=True)
HDRI Environment Setup¶
import bpy
# Get world
world = bpy.context.scene.world
world.use_nodes = True
nodes = world.node_tree.nodes
links = world.node_tree.links
# Clear nodes
nodes.clear()
# Add Environment Texture
env_tex = nodes.new('ShaderNodeTexEnvironment')
env_tex.image = bpy.data.images.load('/path/to/hdri.hdr')
# Add Background node
background = nodes.new('ShaderNodeBackground')
background.inputs['Strength'].default_value = 1.0
# Add Output
output = nodes.new('ShaderNodeOutputWorld')
# Connect
links.new(env_tex.outputs['Color'], background.inputs['Color'])
links.new(background.outputs['Background'], output.inputs['Surface'])
Common Patterns¶
Safe Object Access¶
def get_object_safe(name):
"""Get object by name, returning None if not found."""
return bpy.data.objects.get(name)
# Usage
obj = get_object_safe('MaybeExists')
if obj:
print(f"Found: {obj.name}")
Context Override (Legacy)¶
# For operators that require specific context
# Note: Blender 4.0+ prefers context.temp_override()
# Blender 4.0+
with bpy.context.temp_override(active_object=obj):
bpy.ops.object.mode_set(mode='EDIT')
# Legacy method (pre-4.0)
override = {'active_object': obj, 'object': obj}
bpy.ops.object.mode_set(override, mode='EDIT')
Clean Scene¶
def clean_scene():
"""Remove all objects from scene."""
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
# Also clean orphan data
for mesh in bpy.data.meshes:
if mesh.users == 0:
bpy.data.meshes.remove(mesh)
for mat in bpy.data.materials:
if mat.users == 0:
bpy.data.materials.remove(mat)
Get Scene Info¶
def get_scene_info():
"""Get comprehensive scene information."""
scene = bpy.context.scene
objects = bpy.data.objects
info = {
'scene_name': scene.name,
'frame_current': scene.frame_current,
'frame_start': scene.frame_start,
'frame_end': scene.frame_end,
'render_engine': scene.render.engine,
'objects': []
}
for obj in objects:
obj_info = {
'name': obj.name,
'type': obj.type,
'location': list(obj.location),
'rotation': list(obj.rotation_euler),
'scale': list(obj.scale),
}
info['objects'].append(obj_info)
return info
BlenderForge Integration¶
Using with BlenderForge¶
When using BlenderForge, Python code is executed in Blender's context through the execute_blender_code tool.
Example via AI:
"Execute this code in Blender:
import bpy
bpy.ops.mesh.primitive_cube_add(location=(0, 0, 2))
cube = bpy.context.active_object
cube.name = 'MyCube'"
Common BlenderForge Patterns¶
Create and Position Objects:
import bpy
# Clear selection
bpy.ops.object.select_all(action='DESELECT')
# Create object
bpy.ops.mesh.primitive_cube_add(location=(0, 0, 0), size=2)
obj = bpy.context.active_object
obj.name = "AI_Cube"
Apply Material:
import bpy
# Get or create material
mat_name = "AI_Material"
mat = bpy.data.materials.get(mat_name)
if not mat:
mat = bpy.data.materials.new(name=mat_name)
mat.use_nodes = True
# Set color
bsdf = mat.node_tree.nodes.get('Principled BSDF')
bsdf.inputs['Base Color'].default_value = (1, 0, 0, 1)
# Apply to active object
obj = bpy.context.active_object
if obj.data.materials:
obj.data.materials[0] = mat
else:
obj.data.materials.append(mat)
Scene Query:
import bpy
import json
# Get scene info
info = {
'objects': [
{'name': obj.name, 'type': obj.type}
for obj in bpy.data.objects
]
}
# Output as JSON (for BlenderForge to parse)
print(json.dumps(info))
Resources¶
Official Documentation¶
- Blender Python API: docs.blender.org/api/current
- Blender Manual - Python: docs.blender.org/manual/en/latest/advanced/scripting
Quick Reference¶
- bpy.types: docs.blender.org/api/current/bpy.types.html
- bpy.ops: docs.blender.org/api/current/bpy.ops.html
- bpy.data: docs.blender.org/api/current/bpy.data.html
Community Resources¶
- Blender Stack Exchange: blender.stackexchange.com
- Blender Artists Forum: blenderartists.org
- Blender Developers: developer.blender.org
Learning Resources¶
- Blender Scripting Playlist: YouTube tutorials on Blender Python
- Scripting for Artists: Blender official video series