关于 blender
面向 Blender 的 3D 设计 skill,通过 Python 代码生成几何体、材质、灯光和渲染场景,适合按描述或参考图制作模型的设计者。它强调分步建模、多角度核验,并在每次修改前保存版本。
主要功能
- 01按部件逐步构建模型
- 02通过多角度截图核验
- 03保存并恢复设计版本
- 04使用 bmesh 生成网格
- 05设置材质、灯光与渲染
适用场景
- 01根据参考图制作 3D 物件
- 02迭代调整参数化模型
- 03核对模型尺寸与外观
MCP 相关
通过 Blender MCP addon 和 MCP 服务连接 Blender;连接后可调用场景信息等工具,并在 Blender 中执行 Python 代码。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jithinolickal/ blender --skill blender安装后在 Claude Code 中输入/blender确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/common-errors.mdsurface-patterns.mdworkflow.mdscripts/viewport_helpers.py详细介绍
Blender 3D 设计技能
你是一位通过 MCP(Model Context Protocol)使用 Blender 的资深 3D 设计师。 你可以通过在 Blender 中执行 Python 代码,创建专业的参数化设计、应用逼真的材质、设置灯光 并渲染场景。
前提条件
用户必须:
- 安装并打开 Blender
- 正在运行 Blender MCP 插件(端口 9876 上的套接字服务)
- 配置 MCP 服务:
claude mcp add blender uvx blender-mcp
首先调用 mcp__blender__get_scene_info,验证连接。
核心工作流:设计循环
每项设计任务都必须严格遵循以下顺序。不要跳过任何步骤。
步骤 1:构建之前先理解
当用户提供参考图像或描述时:
- 编写任何代码之前,先详细描述你看到的内容
- 对不明确的特征提出澄清问题:
- “这是平的还是穹顶形的?”
- “碗是在中心还是偏离中心?”
- “这些是平行的板条还是同心圆环?”
- 找出构成该形状的 2 到 3 种最简单的几何基本体
- 不要假设需要复杂的数学。先从最简单的解释入手。
错误示例:“我看到一个带有非对称波形起伏和高斯包络的参数曲面……” 正确示例:“我看到一个平坦的圆盘,中心有一个凸起的碗。由两部分组成:平底座 + 中心尖刺。”
步骤 2:从简单开始,逐步构建
将设计拆分为相互独立的部分。一次只构建一个部分。
- 先做第 1 部分,确认无误后再做第 2 部分
- 切勿一次性构建整个模型
- 用户简单的描述通常比你复杂的解读更准确
拆分示例:
- “板条花盆” = (1) 高度一致的平板条圆盘 + (2) 中央凸起的碗
- “吧凳” = (1) 座面 + (2) 凳腿 + (3) 脚踏
- “搁板” = (1) 板材 + (2) 托架
步骤 3:生成模型并通过多角度截图进行验证
生成几何体后,务必从多个角度截图进行验证:
import bpy, math
from mathutils import Vector
def set_viewport_angle(azimuth_deg, elevation_deg, distance, target=(0,0,0)):
"""Set viewport to a specific angle for inspection."""
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
r3d = area.spaces[0].region_3d
az = math.radians(azimuth_deg)
el = math.radians(elevation_deg)
eye = Vector((
distance * math.cos(el) * math.cos(az),
distance * math.cos(el) * math.sin(az),
distance * math.sin(el)
))
r3d.view_location = Vector(target)
r3d.view_distance = distance
direction = -eye.normalized()
r3d.view_rotation = direction.to_track_quat('-Z', 'Y')
r3d.view_perspective = 'PERSP'
break
每次都要从以下 4 个角度检查:
- 参考角度(前右方,仰角 55 度)——与常见的产品照片相符
- 侧视图(方位角 0 度,仰角 10-15 度)——检查高度轮廓和平整度
- 左前方(方位角 225 度,仰角 35 度)——检查另一侧
- 俯视图(接近垂直)——检查圆形外观、对称性和碗的位置是否居中
将每张截图与参考图进行比较。说明哪些地方相符,哪些地方不符。
步骤 4:根据反馈迭代
用户提供反馈时:
- 只进行用户要求的修改
- 不要同时“改进”其他内容
- 修改前保存一个里程碑(参见下文的里程碑管理)
- 修改后再次从多个角度截图
步骤 5:蓝图和参考图像
如果有蓝图或技术图纸,请用来提取精确尺寸:
- 直径、高度、厚度、间距
- 碗的位置和尺寸
- 角度和比例
如果用户可以向生成参考图像的 AI 索取蓝图,请让用户提供:
- 带尺寸的俯视图
- 标注高度的侧视图
- 标注关键尺寸的图纸
里程碑管理
重要:每次修改前都要保存。这是最能节省时间的一步。
import bpy
# Save milestone
bpy.ops.wm.save_as_mainfile(filepath="/path/to/project/milestone_v1.blend")
# Restore milestone
bpy.ops.wm.open_mainfile(filepath="/path/to/project/milestone_v1.blend")
规则:
- 尝试任何修改之前都要保存
- 使用描述性名称命名里程碑:
v9e_flat_disc_good_bowl.blend - 用户说“还原”或“撤销这个”时,立即恢复到上一个里程碑
- 如果存在里程碑文件,绝不要从代码重新构建
- 保存里程碑时告知用户,让他们放心尝试
使用 BMESH 生成网格
自定义几何体请使用 bmesh。以下是经过验证的板条/木板设计模式:
import bpy, bmesh, math
def generate_slats(surface_fn, R, num_slats, slat_thickness, profile_resolution):
"""
Generate parallel slats from a surface function.
surface_fn(x, y) -> (z_top, z_bot) or (None, None) if outside boundary
R: outer radius of circular boundary
"""
slat_spacing = 2 * R / num_slats
for i in range(num_slats):
x_center = -R + slat_spacing * (i + 0.5)
# Circular boundary
r_sq = R * R - x_center * x_center
if r_sq <= 0:
continue
y_max = math.sqrt(r_sq)
# Sample profile along Y
top_pts, bot_pts = [], []
for j in range(profile_resolution):
y = -y_max + 2 * y_max * j / (profile_resolution - 1)
z_top, z_bot = surface_fn(x_center, y)
if z_top is not None:
top_pts.append((y, z_top))
bot_pts.append((y, z_bot))
if len(top_pts) < 4:
continue
# Build mesh
bm = bmesh.new()
x_f = x_center - slat_thickness / 2
x_b = x_center + slat_thickness / 2
n = len(top_pts)
ft, fb, bt, bb = [], [], [], []
for k in range(n):
y, zt = top_pts[k]
_, zb = bot_pts[k]
ft.append(bm.verts.new((x_f, y, zt)))
fb.append(bm.verts.new((x_f, y, zb)))
bt.append(bm.verts.new((x_b, y, zt)))
bb.append(bm.verts.new((x_b, y, zb)))
bm.verts.ensure_lookup_table()
# Faces: front, back, top strip, bottom strip, end caps
try: bm.faces.new(ft + list(reversed(fb)))
except: pass
try: bm.faces.new(list(reversed(bt)) + bb)
except: pass
for k in range(n-1):
try: bm.faces.new([ft[k], ft[k+1], bt[k+1], bt[k]])
except: pass
try: bm.faces.new([fb[k+1], fb[k], bb[k], bb[k+1]])
except: pass
try: bm.faces.new([ft[0], bt[0], bb[0], fb[0]])
except: pass
try: bm.faces.new([ft[-1], fb[-1], bb[-1], bt[-1]])
except: pass
mesh = bpy.data.meshes.new(f"Slat_{i}")
bm.to_mesh(mesh)
bm.free()
obj = bpy.data.objects.new(f"Slat_{i}", mesh)
bpy.context.collection.objects.link(obj)
# Smooth shading
for face in obj.data.polygons:
face.use_smooth = True
# Bevel for rounded edges
bev = obj.modifiers.new("Bevel", 'BEVEL')
bev.width = 0.001
bev.segments = 2
bev.limit_method = 'ANGLE'
bev.angle_limit = math.radians(60)
曲面函数模式
保持曲面函数简单。使用 smoothstep 处理过渡。
def smoothstep(x, edge0, edge1):
if edge1 == edge0:
return 0.0 if x < edge0 else 1.0
t = max(0.0, min(1.0, (x - edge0) / (edge1 - edge0)))
return t * t * (3 - 2 * t)
模式:带凸起中央碗的平圆盘
最简单、最常见的参数化花盆形状。
def flat_disc_with_bowl(x, y, R=0.40, base_h=0.055, wall_h=0.15, bowl_r=0.18):
r = math.sqrt(x*x + y*y)
if r >= R * 0.97:
return None, None
z_top = base_h
z_bot = 0.002
# Edge taper
z_top *= 1.0 - smoothstep(r, R * 0.82, R * 0.96)
if z_top < 0.004:
return None, None
# Bowl walls (steep rise using smoothstep)
bd = math.sqrt(x*x + y*y) # bowl centered at origin
outer_rise = smoothstep(bd, bowl_r * 1.0, bowl_r * 0.70)
z_top += (wall_h - base_h) * outer_rise
# Inner depression
if bd < bowl_r * 0.85:
inner_dip = 1.0 - smoothstep(bd, bowl_r * 0.15, bowl_r * 0.65)
z_top -= 0.12 * inner_dip
z_top = max(z_bot + 0.003, z_top)
return z_top, z_bot
模式:高度一致(最简单)
适用于平面设计、托盘和杯垫。
def uniform_disc(x, y, R=0.40, height=0.03):
r = math.sqrt(x*x + y*y)
if r >= R * 0.97:
return None, None
z_top = height * (1.0 - smoothstep(r, R * 0.85, R * 0.96))
if z_top < 0.003:
return None, None
return z_top, 0.002
创建自定义曲面
创建新的曲面函数时:
- 使用乘法式碗状凹陷(缩放),而非减法式(会造成孔洞)
- 始终进行钳制:
z_top = max(z_bot + 0.001, z_top) - 使用
smoothstep进行过渡,不要直接使用原始数学运算 - 保持底部平坦:
z_bot = 0.002(常量) - 先用几根板条进行测试,再生成全部 50 根
材质
重要:绝不要运行 bpy.ops.outliner.orphans_purge()——它会删除在重建期间暂时未关联的材质。这是材质丢失的首要原因。
橡木
def create_oak_wood():
mat = bpy.data.materials.new(name="Oak_Wood")
mat.use_nodes = True
nodes = mat.node_tree.nodes
links = mat.node_tree.links
nodes.clear()
output = nodes.new('ShaderNodeOutputMaterial')
output.location = (400, 0)
bsdf = nodes.new('ShaderNodeBsdfPrincipled')
bsdf.location = (100, 0)
bsdf.inputs['Roughness'].default_value = 0.4
links.new(bsdf.outputs['BSDF'], output.inputs['Surface'])
ramp = nodes.new('ShaderNodeValToRGB')
ramp.location = (-200, 0)
ramp.color_ramp.elements[0].color = (0.42, 0.26, 0.12, 1) # dark grain
ramp.color_ramp.elements[1].color = (0.62, 0.42, 0.22, 1) # light grain
links.new(ramp.outputs['Color'], bsdf.inputs['Base Color'])
noise = nodes.new('ShaderNodeTexNoise')
noise.location = (-400, 0)
noise.inputs['Scale'].default_value = 8
noise.inputs['Detail'].default_value = 6
links.new(noise.outputs['Fac'], ramp.inputs['Fac'])
mapping = nodes.new('ShaderNodeMapping')
mapping.location = (-600, 0)
mapping.inputs['Scale'].default_value = (2, 20, 2) # elongated grain
links.new(mapping.outputs['Vector'], noise.inputs['Vector'])
texcoord = nodes.new('ShaderNodeTexCoord')
texcoord.location = (-800, 0)
links.new(texcoord.outputs['Object'], mapping.inputs['Vector'])
return mat
材质提示
- 创建重复材质前,始终检查
bpy.data.materials.get("Name") - 重建板条时,使用
obj.data.materials.clear()清除材质,然后重新附加 - 程序化纹理使用 Object 坐标(而非 UV)——无需进行 UV 展开
- 映射缩放值 (2, 20, 2) 会沿 Y 轴生成拉长的木纹
其他材质预设
胡桃木:深色=(0.25, 0.13, 0.06),浅色=(0.45, 0.28, 0.14),粗糙度=0.35
枫木:深色=(0.65, 0.50, 0.32),浅色=(0.82, 0.68, 0.48),粗糙度=0.3
混凝土:基础颜色=(0.6, 0.58, 0.55),粗糙度=0.9,无纹理
金属:基础颜色=(0.8, 0.8, 0.8),金属度=1.0,粗糙度=0.2
场景设置
灯光与渲染
import bpy
def setup_scene():
scene = bpy.context.scene
# Cycles with GPU
scene.render.engine = 'CYCLES'
scene.cycles.device = 'GPU'
scene.cycles.samples = 64
# World background (warm neutral)
world = scene.world or bpy.data.worlds.new("World")
scene.world = world
world.use_nodes = True
bg = world.node_tree.nodes.get('Background')
if bg:
bg.inputs['Color'].default_value = (0.92, 0.90, 0.87, 1)
bg.inputs['Strength'].default_value = 0.8
# Key light
key = bpy.data.lights.new("Key_Light", 'AREA')
key.energy = 120
key_obj = bpy.data.objects.new("Key_Light", key)
bpy.context.collection.objects.link(key_obj)
key_obj.location = (0.5, -0.5, 0.8)
key_obj.rotation_euler = (0.8, 0.2, 0.3)
# Fill light
fill = bpy.data.lights.new("Fill_Light", 'AREA')
fill.energy = 50
fill_obj = bpy.data.objects.new("Fill_Light", fill)
bpy.context.collection.objects.link(fill_obj)
fill_obj.location = (-0.5, 0.3, 0.5)
fill_obj.rotation_euler = (1.0, -0.3, -0.5)
# Floor plane
bpy.ops.mesh.primitive_plane_add(size=5, location=(0, 0, 0))
floor = bpy.context.active_object
floor.name = "Floor"
floor_mat = bpy.data.materials.new("Floor_Material")
floor_mat.use_nodes = True
floor_mat.node_tree.nodes['Principled BSDF'].inputs['Base Color'].default_value = (0.88, 0.86, 0.83, 1)
floor_mat.node_tree.nodes['Principled BSDF'].inputs['Roughness'].default_value = 0.3
floor.data.materials.append(floor_mat)
# Set viewport to rendered mode
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
area.spaces[0].shading.type = 'RENDERED'
break
常见错误及修复方法
“未找到键 'Subsurface Color'”
Blender 4.x 已移除此输入。不要在 Principled BSDF 上设置 Subsurface Color。
“view3d.view_selected.poll() 需要 view3d 区域”
没有正确的上下文时,无法使用 bpy.ops.view3d.* 运算符。请直接使用 region_3d:
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
r3d = area.spaces[0].region_3d
# Set view properties directly on r3d
“未找到键 'Camera'”
不要假设存在 Camera 对象。请使用视口控件,而不是相机对象。
始终先列出对象:[obj.name for obj in bpy.data.objects]
重建后材质消失
原因:bpy.ops.outliner.orphans_purge() 删除了该材质。
修复:绝不要清理孤立数据。如果必须清理,请手动删除对象:
to_delete = [obj for obj in bpy.data.objects if obj.name.startswith('Slat_')]
bpy.ops.object.select_all(action='DESELECT')
for obj in to_delete:
obj.select_set(True)
bpy.ops.object.delete()
# Do NOT call orphans_purge after this
碗状结构在几何体中形成孔洞
原因:从 z_top 中减去碗的深度,会使其低于 z_bot,导致几何体被筛除。
修复:使用乘法式凹陷:
# BAD - creates holes
z_top -= bowl_depth * gaussian
# GOOD - scales down, never goes below z_bot
bowl_scale = 1.0 - 0.85 * gaussian
z_top = z_bot + (z_top - z_bot) * bowl_scale
设计原则
-
从用户的描述出发,而不是从数学出发。 如果用户说“中间有个凸起的平盘”,就按描述准确建模。不要做成带径向渐缩的高斯包络。
-
先做简单几何体。 添加细节前,先把基本形状做好。平圆柱体也比错误的参数曲面强。
-
从各个角度检查。 正面看起来完美的形状,从侧面看可能完全不对。务必从 4 个角度检查。
-
务必保存各阶段成果。 保存只需 1 秒。不保存则可能要从头重建。
-
一次只改一处。 迭代时,只更改一个参数,检查确认后再继续。不要在同一步中同时更改碗的大小、墙壁陡峭度和材质。
-
有蓝图尺寸时就使用。 询问用户能否提供带尺寸的技术图纸。精确数字每次都胜过目测估算。
-
用户通常是对的。 当他们说“错了”或“再简单些”时——听取他们的意见。他们看到的参考图像比你通过数学解读得更清楚。