返回技能列表
已验证

emergence-blender-bpy

Blender 3D 自动化控制与建模渲染技能。使用 Python 脚本进行程序化建模、材质、灯光与 Cycles/EEVEE 渲染,并支持 3D 打印 STL 导出。由涌现科学出品。

作者
Emergence Science
版本
2.2.0
官方网站
https://emergence.science
代码仓库
https://gitee.com/bubble-universe/emergence-blender-bpy
发布日期
2026年6月3日
最近更新
2026年6月3日
blender3dmodelingrenderingbpyproceduralautomation3d-printingchinese

安装

复制到 OpenClaw
请从 https://gitee.com/bubble-universe/emergence-blender-bpy 安装智能体技能

文档

Technical Manifest

slug emergence-blender-bpy
title Blender 3D 自动化 — Python bpy 脚本控制
description 使用 Blender Python bpy API 进行全面的 3D 自动化控制。包括程序化建模、着色器节点材质、影棚灯光、摄像机控制、照片级 Cycles/EEVEE 渲染及 3D 打印准备。内含齿轮及结晶雪花等代码范例。
version 2.2.0
homepage https://emergence.science/skills/emergence-blender-bpy
repository https://gitee.com/bubble-universe/emergence-blender-bpy
tags blender3dmodelingrenderingbpyproceduralautomation3d-printing
requires {"bins":["blender"]}

Blender Python 自动化控制与设计 (bpy) — v2.2.0

何时使用此技能

当用户或 Agent 需要通过代码来执行以下操作时,调用此技能:

  • 程序化网格建模:生成参数化 3D 物体(例如齿轮、规律结构、建筑构件、分形雪花)。
  • 着色器节点材质:使用节点连接来创建精细的材质纹理(金属、拉丝纹理、透明玻璃、磨砂冰晶)。
  • 影棚三点布光与摄像机设置:搭建三点灯光,配置摄像机并对其进行动态朝向约束。
  • 命令行照片级渲染:无头模式下批量渲染高分辨率静止帧或序列帧。
  • Blender 工作流批处理:导入/导出资产并执行自动化几何清理。
  • 3D 打印导出:应用 Solidify 与 Decimate 等修改器,并导出适合切片的 watertight (紧密闭合) STL 模型。

前提条件

# 安装 Blender 4.0 或更高版本
apt-get install blender   # Linux (Debian/Ubuntu)
# 或: brew install blender  # macOS

# 验证安装
blender --version

核心开发模式

1. 无头(后台)命令行运行

在没有图形界面的服务器或后台任务中执行脚本:

blender --background --python script.py

2. 场景初始化与清理

在新建任何模型前,清空场景中所有默认的物体、相机、灯光和旧材质:

import bpy

# 选择所有物体并删除
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)

# 清理残留的材质数据块
for mat in list(bpy.data.materials):
    bpy.data.materials.remove(mat)

3. 程序化齿轮网格创建

通过选定角度上的面进行挤出(Extrude)和缩放,程序化创建规则齿轮:

import bpy
import math

def create_gear(name, radius=2.0, teeth=16, thickness=0.8):
    """创建带轴孔的齿轮网格"""
    # 添加基础圆柱体
    bpy.ops.mesh.primitive_cylinder_add(
        vertices=teeth * 4,
        radius=radius,
        depth=thickness,
        location=(0, 0, 0)
    )
    gear = bpy.context.object
    gear.name = name
    
    # 进入编辑模式以选择特定齿顶面进行挤出
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action='DESELECT')
    
    # 根据顶点夹角计算并选中齿的位置
    for v in gear.data.vertices:
        angle = math.atan2(v.co.y, v.co.x)
        tooth_angle = 2 * math.pi / teeth
        angle_diff = abs((angle % tooth_angle) - tooth_angle / 2)
        if angle_diff < tooth_angle * 0.35:
            v.select = True
            
    # 挤出并向外缩放生成齿牙
    bpy.ops.mesh.extrude_region_move(
        TRANSFORM_OT_translate={"value": (0, 0, 0)}
    )
    bpy.ops.transform.resize(
        value=((radius + 0.4) / radius,) * 2 + (1,),
        orient_type='GLOBAL'
    )
    bpy.ops.object.mode_set(mode='OBJECT')
    
    # 使用布尔(Boolean)修改器开凿中心轴孔
    bpy.ops.mesh.primitive_cylinder_add(
        vertices=32, radius=0.5,
        depth=thickness * 1.5, location=(0, 0, 0)
    )
    cutter = bpy.context.object
    
    bool_mod = gear.modifiers.new(name="Hole", type='BOOLEAN')
    bool_mod.operation = 'DIFFERENCE'
    bool_mod.object = cutter
    
    bpy.context.view_layer.objects.active = gear
    gear.select_set(True)
    bpy.ops.object.modifier_apply(modifier="Hole")
    bpy.data.objects.remove(cutter, do_unlink=True)
    
    # 追加倒角 (Bevel) 和表面细分 (Subdivision) 修改器以圆滑边缘
    bevel = gear.modifiers.new(name="Bevel", type='BEVEL')
    bevel.width = 0.05
    bevel.segments = 2
    bevel.limit_method = 'ANGLE'
    
    subdiv = gear.modifiers.new(name="Subdivision", type='SUBSURF')
    subdiv.levels = 1
    subdiv.render_levels = 2
    
    return gear

4. 程序化金属材质(节点着色器)

使用着色器节点树动态生成带拉丝纹理的金属材质:

def create_metal_material(name, base_color, metallic=0.85, roughness=0.25,
                          noise_scale=30.0, use_brushed=True):
    """创建带噪波拉丝金属质感材质"""
    mat = bpy.data.materials.new(name=name)
    mat.use_nodes = True
    nodes = mat.node_tree.nodes
    links = mat.node_tree.links
    nodes.clear()
    
    # 材质输出节点
    output = nodes.new(type='ShaderNodeOutputMaterial')
    output.location = (400, 0)
    
    # Principled BSDF(原理化 BSDF)节点
    bsdf = nodes.new(type='ShaderNodeBsdfPrincipled')
    bsdf.location = (0, 0)
    bsdf.inputs['Base Color'].default_value = base_color
    bsdf.inputs['Metallic'].default_value = metallic
    bsdf.inputs['Roughness'].default_value = roughness
    
    # 加入拉丝纹理噪波
    if use_brushed:
        tex_coord = nodes.new(type='ShaderNodeTexCoord')
        tex_coord.location = (-400, 100)
        noise = nodes.new(type='ShaderNodeTexNoise')
        noise.location = (-200, 0)
        noise.inputs['Scale'].default_value = noise_scale
        noise.inputs['Detail'].default_value = 2.0
        
        ramp = nodes.new(type='ShaderNodeValToRGB')
        ramp.location = (0, 100)
        ramp.color_ramp.elements[0].color = (
            base_color[0]*0.8, base_color[1]*0.8, base_color[2]*0.8, 1.0)
        ramp.color_ramp.elements[1].color = (
            base_color[0]*1.1, base_color[1]*1.1, base_color[2]*1.1, 1.0)
        
        links.new(tex_coord.outputs['Object'], noise.inputs['Vector'])
        links.new(noise.outputs['Fac'], ramp.inputs['Fac'])
        links.new(ramp.outputs['Color'], bsdf.inputs['Base Color'])
        
    links.new(bsdf.outputs['BSDF'], output.inputs['Surface'])
    return mat

5. 三点影棚光源设置

通过主光(Key Light)、辅光(Fill Light)和轮廓光(Rim Light)突出主体的反射与物理轮廓:

def setup_lighting(base_intensity=600):
    """标准的影棚三点光源搭建"""
    # 主光源(前侧方,强度最大,决定阴影方向)
    key = bpy.ops.object.light_add(
        type='AREA', location=(5, -4, 6),
        rotation=(0.8, 0, 0.7))
    key = bpy.context.object
    key.data.energy = base_intensity
    key.data.size = 4
    
    # 辅助光源(另一侧前侧方,较弱,用以照亮阴影)
    fill = bpy.ops.object.light_add(
        type='AREA', location=(-4, 3, 3),
        rotation=(0.5, 0, -1.0))
    fill = bpy.context.object
    fill.data.energy = base_intensity * 0.5
    fill.data.size = 3
    
    # 轮廓/背光(主体后上方,用来勾勒轮廓发光边)
    rim = bpy.ops.object.light_add(
        type='AREA', location=(0, 5, 5),
        rotation=(0.5, 0, 1.57))
    rim = bpy.context.object
    rim.data.energy = base_intensity * 0.4
    rim.data.size = 2

6. 摄像机设置与动态 Target 朝向追踪

根据目标位置,通过四元数数学公式自动调整摄像机俯仰和偏航角,对齐拍摄中心:

import mathutils

def setup_camera(location=(5.5, -4.5, 3.5), target=(0, 0, 0)):
    bpy.ops.object.camera_add(location=location)
    cam = bpy.context.object
    
    # 根据朝向向量计算四元数轨道,自动调整旋转角
    direction = mathutils.Vector(target) - cam.location
    rot_quat = direction.to_track_quat('-Z', 'Y')
    cam.rotation_euler = rot_quat.to_euler()
    
    bpy.context.scene.camera = cam
    return cam

7. Cycles & EEVEE 图像渲染与 Mac Metal GPU 加速

配置底层物理渲染引擎属性,并对 macOS 上的 Apple Silicon 芯片进行 Metal 加速优化:

def render(output_path="/tmp/render.png", engine='CYCLES',
           width=1080, height=1080, samples=64):
    scene = bpy.context.scene
    scene.render.engine = engine
    scene.render.resolution_x = width
    scene.render.resolution_y = height
    scene.render.filepath = output_path
    scene.render.image_settings.file_format = 'PNG'
    
    if engine == 'CYCLES':
        scene.cycles.samples = samples
        scene.cycles.use_denoising = True
        
        # 激活 macOS Metal GPU 并检测可用核心
        try:
            bpy.context.preferences.addons['cycles'].preferences.compute_device_type = 'METAL'
            bpy.context.preferences.addons['cycles'].preferences.get_devices()
            for d in bpy.context.preferences.addons['cycles'].preferences.devices:
                if d.type == 'METAL':
                    d.use = True
        except Exception:
            pass
            
    bpy.ops.render.render(write_still=True)

8. 折射玻璃/冰晶节点材质(Transmission/IOR)

创建支持高物理精确度的折射玻璃和冰雪材质(通过 Transmission 穿透属性):

def create_glass_material(name="Glass", color=(0.9, 0.95, 1.0, 1.0), roughness=0.1, ior=1.309):
    """创建物理折射玻璃或冰晶材质。IOR 折射率:1.309(冰),1.5(玻璃)"""
    mat = bpy.data.materials.new(name=name)
    mat.use_nodes = True
    nodes = mat.node_tree.nodes
    links = mat.node_tree.links
    nodes.clear()
    
    bsdf = nodes.new(type='ShaderNodeBsdfPrincipled')
    output = nodes.new(type='ShaderNodeOutputMaterial')
    links.new(bsdf.outputs['BSDF'], output.inputs['Surface'])
    
    bsdf.inputs['Base Color'].default_value = color
    bsdf.inputs['Roughness'].default_value = roughness
    bsdf.inputs['IOR'].default_value = ior
    
    # 启用光线穿透 (Transmission Weight)
    if 'Transmission Weight' in bsdf.inputs:
        bsdf.inputs['Transmission Weight'].default_value = 1.0
    elif 'Transmission' in bsdf.inputs:
        bsdf.inputs['Transmission'].default_value = 1.0
        
    return mat

9. 进阶布尔建模(逐一雕刻与多余溢出边界)

在网格上用其他复杂几何体(如管道、环线)雕刻缝隙时:

  • 避免一次性整体剪切:如果一次性差集减去一个自身有重叠的复杂网格(例如相互交叉的细管),会导致 EXACT 布尔求解器异常,把整个主网格完全删掉(网格顶点数变为 0)。应该对多条环线进行逐一应用布尔削减
  • 边界必须多余溢出:切割体(Cutter)在切出缝隙时,尺寸边缘一定要超出被切割物的边界外(即更大、更深),切面重合会导致浮点数精度重合,进而导致 EXACT 求解器求解失效而无法切出缝隙。
  • 端点加盖:在将样条曲线(Curves)转为网格切割前,必须声明 curve_data.use_fill_caps = True 对管道端点加盖,结合细分修改器(Subdivision)可以在端部刻出圆滑过渡。

10. 100% 程序化纹理空间着色器缝隙(免网格切割)

对于球体等规则几何体,为避免切割引起的网格破损和拓扑混乱,优先推荐直接在着色器节点(Shader Nodes)中用物体空间坐标(Object Coordinates)数学公式计算并贴图混合出接缝:

  • 篮球缝隙线计算几何公式: $$|x| = \sqrt{1 - z^2} \cos\left(\theta \sqrt{1 - z^2}\right)$$
  • 贴图映射与渐变蒙版:将以上距离公式输出映射至 SMOOTHERSTEP 差值节点,设定宽度范围得到平滑渐变蒙版。用此蒙版分别去混合基础底色(橘红与黑色接缝)和高度图输入(送入 Bump 节点产生法线凹陷)。

11. 3D 打印准备与闭合流形导出(Solidify与Decimate修改器)

为 3D 打印(如 FDM/SLA)建模时:

  • 设定物理比例尺:显式指定系统单位 scale,一般以 1 个 Blender 单位代表 1 cm 或 1 mm:
    scene = bpy.context.scene
    scene.unit_settings.system = 'METRIC'
    scene.unit_settings.scale_length = 0.01  # 1个单位 = 1 cm
    
  • 外壳固化与壁厚:3D 打印无法打印厚度为 0 的数学面片。使用 Solidify 修改器赋予壁厚(例如 FDM 打印机最低要求 1.2mm 至 2.0mm 壁厚):
    solid = obj.modifiers.new(name="Solidify", type='SOLIDIFY')
    solid.thickness = 0.12  # 如果 1 个单位 = 1 cm,这里代表 1.2 mm 壁厚
    solid.offset = -1.0     # 向内收缩固化
    
  • 多边形面数精简:顶点数过高会导致切片软件卡死。在导出前,必须使用 Decimate 修改器按百分比削减多边形面数:
    decimate = obj.modifiers.new(name="Decimate", type='DECIMATE')
    decimate.ratio = 0.15   # 仅保留原本 15% 的面
    
  • Watertight STL 导出:确保网格闭合流形后,使用标准命令导出 STL:
    # Blender 4.0+
    bpy.ops.wm.stl_export(filepath="model.stl", export_selected=True)
    # 旧版本 Blender:
    # bpy.ops.export_mesh.stl(filepath="model.stl", use_selection=True)
    

12. 程序化导入三视图背景参考图

若要根据角色原画或三视图进行对齐手工程序建模,可以通过脚本将前视、侧视、顶视图片载入为空背景图(Empty Image Object):

def load_reference_image(filepath, name="ReferenceImage", location=(0, 0, 0), rotation=(1.5708, 0, 0)):
    # 添加一个 IMAGE 类型的 Empty 空物体
    bpy.ops.object.empty_add(type='IMAGE', location=location, rotation=rotation)
    empty = bpy.context.object
    empty.name = name
    
    # 加载图片并将其分配给空物体
    try:
        img = bpy.data.images.load(filepath)
        empty.data = img
        empty.empty_display_size = 5.0
        empty.use_empty_image_alpha = True
        empty.empty_image_depth = 'BACK'  # 保证参考图显示在模型后面
    except Exception as e:
        print(f"载入参考图失败: {e}")

渲染引擎对比选择

引擎适用场景说明
BLENDER_EEVEE快速预览、实时动画渲染耗时只需 <1 秒,不支持物理折射,适合几何框架的快速核验。
CYCLES照片级真实感渲染折射玻璃、冰晶、反射重合等的唯一选择。建议配置 samples=64 并开启降噪 (Denoising)。

常见问题与排错排坑

  • 布尔差集操作后整个模型消失(顶点数 vertices 变为 0)
    • 原由:切割体(Cutter)存在自相交,或者切割面的边界和被切模型表面刚好完全重合(Co-incident surface)。
    • 解决:检查切割体的网格自交,将布尔解算器(Solver)从 'EXACT' 切换至 'FLOAT' (旧版叫 'FAST'),或者微调切割体位置使其完全溢出重叠。
  • 样条曲线 (Curve) 转化为网格后变为了空心细管
    • 原由:曲线数据在转换前未进行端点加盖。
    • 解决:在运行 convert 转化前,将曲线数据的加盖参数置为真:curve_data.use_fill_caps = True
  • 透明玻璃或冰晶材质渲染出来一片漆黑或扁平
    • 原由:折射材质非常依赖背景光照与反光的面。
    • 解决:必须使用 Cycles 渲染器。在模型下方放置一底面板(如 Roughness=0.2, Metallic=0.9 的暗色反射面),并在模型正后上方设置一高强度的轮廓区域背光(Rim Light),光线穿透折射后边缘才会闪闪发光。
  • 脚本在不同 Blender 版本之间运行时报错
    • 原由:Blender 版本的 bpy API 时常有破坏性更新(例如材质 use_nodes 弃用、STL 导出指令修改)。
    • 解决:在脚本中优先加入 Python try-except 或版本属性检测(如 bpy.app.version)来做兼容适配。

可验证性证明

该技能已通过涌现科学结算中心的分析和验证。它遵循通用惊奇协议(Surprisal Protocol),确保确定性的智能体执行和安全的数据处理。