返回技能列表

script-blender-automation

pjt222
更新于 2 days ago
8 次查看
17
2
17
在 GitHub 上查看
apiautomationdesigndata

关于

This skill generates Blender Python scripts using the bpy API to automate procedural modeling, animation, and batch processing tasks. It is designed for automating repetitive workflows, creating custom add-ons, and integrating Blender with external data pipelines. Use it for advanced automation like generating geometry from algorithms or setting up batch rendering with parameter variations.

快速安装

Claude Code

推荐
主要方式
npx skills add pjt222/agent-almanac -a claude-code
插件命令备选方式
/plugin add https://github.com/pjt222/agent-almanac
Git 克隆备选方式
git clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/script-blender-automation

在 Claude Code 中复制并粘贴此命令以安装该技能

技能文档

Script Blender Automation

Advanced Blender Python scripting for procedural modeling, keyframe animation, batch ops, operator registration, add-on development. Covers complex geometry generation, automated workflows, integration with external data sources.

When Use

  • Automating repetitive modeling or animation tasks
  • Generating procedural geometry from algorithms or data
  • Creating batch rendering pipelines with parameter variations
  • Building custom operators or add-ons for workflow enhancement
  • Integrating Blender with external data pipelines or APIs
  • Scripting complex animations with mathematical precision
  • Developing reusable tools for team workflows

Inputs

InputTypeDescriptionExample
Automation requirementsSpecificationTask description, parameters, constraintsRender 100 variations, animate path from data
Data sourcesFiles/APIsExternal data for procedural generationCSV coordinates, JSON parameters, API responses
Algorithm definitionsCode/MathProcedural generation logicFractal patterns, parametric curves, L-systems
Operator specificationsRequirementsCustom tool behavior and UITool name, properties, modal interaction
Animation parametersKeyframes/DataTiming, easing, constraintsFrame ranges, interpolation curves

Steps

1. Procedural Geometry Generation

Make mesh geometry programmatically with BMesh.

import bpy
import bmesh
import math

def create_parametric_surface(name, u_res=32, v_res=32):
    """Generate parametric surface using mathematical function."""
    mesh = bpy.data.meshes.new(name)
    obj = bpy.data.objects.new(name, mesh)
    bpy.context.collection.objects.link(obj)

    bm = bmesh.new()

    # Create vertices using parametric equations
    verts = []
    for i in range(u_res):
        for j in range(v_res):
            u = (i / (u_res - 1)) * 2 * math.pi
            v = (j / (v_res - 1)) * math.pi

            # Sphere parametric equations
            x = math.sin(v) * math.cos(u)
            y = math.sin(v) * math.sin(u)
            z = math.cos(v)

            vert = bm.verts.new((x, y, z))
            verts.append(vert)

    # Create faces
    bm.verts.ensure_lookup_table()
    for i in range(u_res - 1):
        for j in range(v_res - 1):
            v1 = verts[i * v_res + j]
            v2 = verts[(i + 1) * v_res + j]
            v3 = verts[(i + 1) * v_res + (j + 1)]
            v4 = verts[i * v_res + (j + 1)]
            bm.faces.new([v1, v2, v3, v4])

    # Write to mesh
    bm.to_mesh(mesh)
    bm.free()

    return obj

Got: Complex geometry generated from math functions

If fail: Check BMesh API calls, verify vertex indexing, ensure faces manifold

2. Keyframe Animation Automation

Script animation keyframes + drivers.

def animate_rotation(obj, start_frame=1, end_frame=250, axis='Z', rotations=2):
    """Animate object rotation over time."""
    # Set initial keyframe
    obj.rotation_euler[2] = 0  # Z axis
    obj.keyframe_insert(data_path="rotation_euler", index=2, frame=start_frame)

    # Set end keyframe
    obj.rotation_euler[2] = rotations * 2 * math.pi
    obj.keyframe_insert(data_path="rotation_euler", index=2, frame=end_frame)

    # Set interpolation
    if obj.animation_data and obj.animation_data.action:
        for fcurve in obj.animation_data.action.fcurves:
            if 'rotation_euler' in fcurve.data_path:
                for keyframe in fcurve.keyframe_points:
                    keyframe.interpolation = 'LINEAR'

def animate_material_property(mat, property_path, values, frames):
    """Animate material node values."""
    if not mat.node_tree:
        return

    # Example: animate emission strength
    nodes = mat.node_tree.nodes
    emission = nodes.get('Emission')
    if emission:
        for frame, value in zip(frames, values):
            emission.inputs['Strength'].default_value = value
            emission.inputs['Strength'].keyframe_insert(
                data_path="default_value",
                frame=frame
            )

def create_driver(obj, property_path, expression):
    """Create driver for automated animation."""
    driver = obj.driver_add(property_path)
    driver.driver.type = 'SCRIPTED'
    driver.driver.expression = expression

    # Example: link rotation to frame number
    # expression = "frame / 10"

Got: Keyframes inserted, animation plays back correct

If fail: Check property paths, verify data_path syntax, ensure objects keyable

3. Batch Processing Operations

Process multiple objects or files in batch.

import os
from pathlib import Path

def batch_import_and_render(input_dir, output_dir, file_pattern="*.obj"):
    """Import multiple files and render each."""
    input_path = Path(input_dir)
    output_path = Path(output_dir)
    output_path.mkdir(exist_ok=True)

    scene = bpy.context.scene

    for obj_file in input_path.glob(file_pattern):
        # Clear existing objects
        bpy.ops.object.select_all(action='SELECT')
        bpy.ops.object.delete()

        # Import model
        bpy.ops.import_scene.obj(filepath=str(obj_file))

        # Setup camera and lighting (reuse setup functions)
        setup_camera()
        setup_lighting()

        # Render
        output_file = output_path / f"{obj_file.stem}.png"
        scene.render.filepath = str(output_file)
        bpy.ops.render.render(write_still=True)

        print(f"Rendered: {output_file}")

def batch_material_variation(base_object, colors, output_prefix):
    """Render object with multiple material colors."""
    mat = base_object.data.materials[0]
    bsdf = mat.node_tree.nodes.get('Principled BSDF')

    if not bsdf:
        return

    for i, color in enumerate(colors):
        # Update material color
        bsdf.inputs['Base Color'].default_value = color + (1.0,)

        # Render
        bpy.context.scene.render.filepath = f"{output_prefix}_{i:03d}.png"
        bpy.ops.render.render(write_still=True)

Got: Multiple files processed, renders made for each variant

If fail: Check file paths exist, verify import operators, handle missing materials

4. Custom Operator Development

Make custom operators for reusable tools.

import bpy
from bpy.props import FloatProperty, IntProperty

class OBJECT_OT_generate_spiral(bpy.types.Operator):
    """Generate a spiral curve"""
    bl_idname = "object.generate_spiral"
    bl_label = "Generate Spiral"
    bl_options = {'REGISTER', 'UNDO'}

    # Operator properties
    radius: FloatProperty(
        name="Radius",
        description="Spiral radius",
        default=2.0,
        min=0.1,
        max=10.0
    )

    turns: IntProperty(
        name="Turns",
        description="Number of spiral turns",
        default=5,
        min=1,
        max=20
    )

    resolution: IntProperty(
        name="Resolution",
        description="Points per turn",
        default=32,
        min=8,
        max=128
    )

    def execute(self, context):
        # Create curve
        curve = bpy.data.curves.new('Spiral', 'CURVE')
        curve.dimensions = '3D'

        spline = curve.splines.new('NURBS')
        num_points = self.turns * self.resolution

        spline.points.add(num_points - 1)  # -1 because one point exists

        for i in range(num_points):
            t = i / self.resolution
            angle = t * 2 * math.pi

            x = self.radius * math.cos(angle)
            y = self.radius * math.sin(angle)
            z = t * 0.5

            spline.points[i].co = (x, y, z, 1.0)

        # Create object
        obj = bpy.data.objects.new('Spiral', curve)
        context.collection.objects.link(obj)
        obj.select_set(True)
        context.view_layer.objects.active = obj

        self.report({'INFO'}, f"Generated spiral with {num_points} points")
        return {'FINISHED'}

def register():
    bpy.utils.register_class(OBJECT_OT_generate_spiral)

def unregister():
    bpy.utils.unregister_class(OBJECT_OT_generate_spiral)

if __name__ == "__main__":
    register()

Got: Operator appears in search, executes with proper undo support

If fail: Check bl_idname format (lowercase with underscores), verify property types

5. Modal Operator for Interactive Tools

Make interactive modal operators.

class OBJECT_OT_modal_scale(bpy.types.Operator):
    """Interactive scaling with mouse"""
    bl_idname = "object.modal_scale"
    bl_label = "Modal Scale"
    bl_options = {'REGISTER', 'UNDO'}

    def __init__(self):
        self.initial_mouse_x = 0
        self.initial_scale = 1.0

    def modal(self, context, event):
        if event.type == 'MOUSEMOVE':
            # Calculate scale based on mouse movement
            delta = event.mouse_x - self.initial_mouse_x
            scale = self.initial_scale + (delta / 100.0)
            scale = max(0.1, scale)  # Minimum scale

            # Apply to active object
            context.active_object.scale = (scale, scale, scale)

        elif event.type == 'LEFTMOUSE':
            return {'FINISHED'}

        elif event.type in {'RIGHTMOUSE', 'ESC'}:
            # Cancel - restore initial scale
            context.active_object.scale = (
                self.initial_scale,
                self.initial_scale,
                self.initial_scale
            )
            return {'CANCELLED'}

        return {'RUNNING_MODAL'}

    def invoke(self, context, event):
        if context.active_object:
            self.initial_mouse_x = event.mouse_x
            self.initial_scale = context.active_object.scale[0]

            context.window_manager.modal_handler_add(self)
            return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, "No active object")
            return {'CANCELLED'}

Got: Interactive operator responds to mouse, left-click confirms, ESC cancels

If fail: Check event types, ensure modal handler added, handle no active object

6. Add-on Packaging

Structure code as installable add-on.

bl_info = {
    "name": "Custom Tools",
    "author": "Your Name",
    "version": (1, 0, 0),
    "blender": (3, 0, 0),
    "location": "View3D > Add > Mesh",
    "description": "Collection of custom modeling tools",
    "category": "Add Mesh",
}

import bpy

# Import operator classes
from .operators import OBJECT_OT_generate_spiral

classes = (
    OBJECT_OT_generate_spiral,
    # Add other classes
)

def menu_func(self, context):
    """Add to menu."""
    self.layout.operator(OBJECT_OT_generate_spiral.bl_idname)

def register():
    for cls in classes:
        bpy.utils.register_class(cls)

    bpy.types.VIEW3D_MT_mesh_add.append(menu_func)

def unregister():
    bpy.types.VIEW3D_MT_mesh_add.remove(menu_func)

    for cls in reversed(classes):
        bpy.utils.unregister_class(cls)

if __name__ == "__main__":
    register()

Got: Add-on installs via Preferences, operators appear in menus

If fail: Check bl_info format, verify Blender version requirement, ensure all classes listed

7. Data-Driven Procedural Generation

Generate geometry from external data.

import csv
import json

def create_from_csv(filepath):
    """Generate objects from CSV data."""
    with open(filepath, 'r') as f:
        reader = csv.DictReader(f)

        for row in reader:
            # Parse data
            name = row['name']
            x, y, z = float(row['x']), float(row['y']), float(row['z'])
            scale = float(row.get('scale', 1.0))

            # Create object
            bpy.ops.mesh.primitive_uv_sphere_add(location=(x, y, z))
            obj = bpy.context.active_object
            obj.name = name
            obj.scale = (scale, scale, scale)

def create_from_json(filepath):
    """Generate scene from JSON configuration."""
    with open(filepath, 'r') as f:
        config = json.load(f)

    # Process objects
    for obj_config in config.get('objects', []):
        obj_type = obj_config['type']
        location = obj_config['location']

        if obj_type == 'cube':
            bpy.ops.mesh.primitive_cube_add(location=location)
        elif obj_type == 'sphere':
            bpy.ops.mesh.primitive_uv_sphere_add(location=location)

        obj = bpy.context.active_object
        obj.name = obj_config.get('name', 'Object')

        # Apply material if specified
        if 'material' in obj_config:
            mat_name = obj_config['material']
            mat = bpy.data.materials.get(mat_name)
            if mat:
                obj.data.materials.append(mat)

Got: Objects made based on external data files

If fail: Validate file format, handle missing fields, provide defaults

Checks

  • Scripts run without errors in Blender Python env
  • Procedural geometry generates as expected
  • Animation keyframes inserted at correct frames
  • Batch ops process all files successfully
  • Custom operators appear in search, execute correct
  • Modal operators respond to mouse/keyboard events
  • Add-ons install + uninstall cleanly
  • External data files parsed correct
  • Error handling covers edge cases
  • Code follows PEP 8 style

Pitfalls

  1. Circular imports in add-ons: Use relative imports, structure modules carefully
  2. Operator naming: bl_idname must be lowercase with single underscore (category.name)
  3. Property types: Use correct bpy.props types (FloatProperty, IntProperty, etc.)
  4. Context access: Not all operators work in all contexts (viewport vs render)
  5. BMesh cleanup: Always call bm.free() after bm.to_mesh() to prevent memory leaks
  6. Animation keyframe timing: Frame numbers start at 1, not 0
  7. Driver expression errors: Validate expressions, use safe namespace
  8. Modal operator blocking: Do not block in modal(), use non-blocking ops
  9. Add-on installation paths: Place in Blender's scripts/addons directory
  10. Version compatibility: API changes between Blender versions, document requirements

See Also

GitHub 仓库

pjt222/agent-almanac
路径: i18n/caveman/skills/script-blender-automation
0
agentsagentskillsai-assisted-developmentclaude-codeskillsteams

相关推荐技能

content-collections

Content Collections 是一个 TypeScript 优先的构建工具,可将本地 Markdown/MDX 文件转换为类型安全的数据集合。它专为构建博客、文档站和内容密集型 Vite+React 应用而设计,提供基于 Zod 的自动模式验证。该工具涵盖从 Vite 插件配置、MDX 编译到生产环境部署的完整工作流。

查看技能

polymarket

这个Claude Skill为开发者提供完整的Polymarket预测市场开发支持,涵盖API调用、交易执行和市场数据分析。关键特性包括实时WebSocket数据流,可监控实时交易、订单和市场动态。开发者可用它构建预测市场应用、实施交易策略并集成实时市场预测功能。

查看技能

creating-opencode-plugins

该Skill帮助开发者创建OpenCode插件,用于接入命令、文件、LSP等25+种事件。它提供了插件结构、事件API规范和JavaScript/TypeScript实现模式,适合需要拦截操作、扩展功能或自定义事件处理的场景。开发者可通过它快速构建响应式模块来增强OpenCode AI助手的能力。

查看技能

sglang

SGLang是一个专为LLM设计的高性能推理框架,特别适用于需要结构化输出的场景。它通过RadixAttention前缀缓存技术,在处理JSON、正则表达式、工具调用等具有重复前缀的复杂工作流时,能实现极速生成。如果你正在构建智能体或多轮对话系统,并追求远超vLLM的推理性能,SGLang是理想选择。

查看技能