mcpField
B
blender-3d-modeling

blender-3d-modeling

github.com/andrew1326创意与媒体3159 次安装4 周前更新
代码仓库

关于 blender-3d-modeling

此技能使用 Blender 的 Python API 程序化创建 3D 几何体,涵盖网格构建、bmesh 编辑、修改器和曲线。适合希望通过代码生成模型的艺术创作者与技术用户。

主要功能

  1. 01根据顶点和面数据构建网格
  2. 02使用 bmesh 编辑几何体
  3. 03通过 Python 应用修改器
  4. 04生成曲线与曲面
  5. 05创建参数化图案和地形
  6. 06为网格面指定材质

适用场景

  1. 01生成参数化楼梯
  2. 02创建蜂窝面板
  3. 03构建网格或圆形物体阵列
  4. 04根据高度图生成地形

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/andrew1326/dominations --skill blender-3d-modeling

安装后在 Claude Code 中输入/blender-3d-modeling确认已加载。

详细介绍

Blender 3D 建模

概述

使用 Blender 的 Python API 以程序化方式创建 3D 几何体。从顶点和面构建网格,使用 bmesh 进行高级编辑,应用修改器,生成曲线,并完全通过代码创建参数化或程序化模型。

说明

1. 从原始顶点数据创建网格
import bpy

vertices = [
    (-1, -1, 0), (1, -1, 0), (1, 1, 0), (-1, 1, 0),  # bottom
    (-1, -1, 2), (1, -1, 2), (1, 1, 2), (-1, 1, 2),   # top
]
faces = [
    (0, 1, 2, 3),  # bottom
    (4, 5, 6, 7),  # top
    (0, 1, 5, 4),  # front
    (2, 3, 7, 6),  # back
    (0, 3, 7, 4),  # left
    (1, 2, 6, 5),  # right
]

mesh = bpy.data.meshes.new("CustomBox")
mesh.from_pydata(vertices, [], faces)
mesh.update()

obj = bpy.data.objects.new("CustomBox", mesh)
bpy.context.collection.objects.link(obj)

from_pydata(vertices, edges, faces) 是构建网格的主要方式。如果不需要边或面,请传入空列表 []。

2. 使用 bmesh 进行高级网格编辑
import bpy
import bmesh

# Create from scratch
bm = bmesh.new()

# Or edit an existing mesh
obj = bpy.context.active_object
bm = bmesh.new()
bm.from_mesh(obj.data)

# Add geometry
v1 = bm.verts.new((0, 0, 0))
v2 = bm.verts.new((1, 0, 0))
v3 = bm.verts.new((1, 1, 0))
v4 = bm.verts.new((0, 1, 0))
bm.faces.new((v1, v2, v3, v4))

# Common operations
bmesh.ops.extrude_face_region(bm, geom=bm.faces[:])
bmesh.ops.translate(bm, vec=(0, 0, 1), verts=[v for v in bm.verts if v.select])
bmesh.ops.subdivide_edges(bm, edges=bm.edges[:], cuts=2)

# Write back to mesh
bm.to_mesh(obj.data)
bm.free()
obj.data.update()

完成后务必调用 bm.free() 以释放内存。

3. 以程序化方式应用修改器
import bpy

obj = bpy.context.active_object

# Subdivision Surface
sub = obj.modifiers.new(name="Subdivision", type='SUBSURF')
sub.levels = 2
sub.render_levels = 3

# Mirror
mirror = obj.modifiers.new(name="Mirror", type='MIRROR')
mirror.use_axis = (True, False, False)
mirror.use_clip = True

# Array
array = obj.modifiers.new(name="Array", type='ARRAY')
array.count = 5
array.relative_offset_displace = (1.1, 0, 0)

# Boolean
bool_mod = obj.modifiers.new(name="Boolean", type='BOOLEAN')
bool_mod.operation = 'DIFFERENCE'
bool_mod.object = bpy.data.objects["Cutter"]

# Solidify
solid = obj.modifiers.new(name="Solidify", type='SOLIDIFY')
solid.thickness = 0.1

# Bevel
bevel = obj.modifiers.new(name="Bevel", type='BEVEL')
bevel.width = 0.05
bevel.segments = 3

# Apply a modifier permanently
bpy.context.view_layer.objects.active = obj
bpy.ops.object.modifier_apply(modifier="Subdivision")
4. 创建曲线和曲面
import bpy
import math

# Create a bezier curve
curve_data = bpy.data.curves.new("MyCurve", type='CURVE')
curve_data.dimensions = '3D'
curve_data.resolution_u = 24

spline = curve_data.splines.new('BEZIER')
spline.bezier_points.add(3)  # 4 points total (1 default + 3 added)

coords = [(0, 0, 0), (1, 1, 0), (2, 0, 1), (3, 1, 1)]
for i, (x, y, z) in enumerate(coords):
    pt = spline.bezier_points[i]
    pt.co = (x, y, z)
    pt.handle_type_left = 'AUTO'
    pt.handle_type_right = 'AUTO'

# Add depth to make it a tube
curve_data.bevel_depth = 0.1
curve_data.bevel_resolution = 4

obj = bpy.data.objects.new("MyCurve", curve_data)
bpy.context.collection.objects.link(obj)

# Create a NURBS circle
bpy.ops.curve.primitive_nurbs_circle_add(radius=2)
circle = bpy.context.active_object
circle.data.bevel_depth = 0.05
5. 程序化生成模式

对象网格:

import bpy

rows, cols = 10, 10
spacing = 2.5

for i in range(rows):
    for j in range(cols):
        bpy.ops.mesh.primitive_cube_add(
            size=1,
            location=(i * spacing, j * spacing, 0)
        )
        obj = bpy.context.active_object
        obj.name = f"Grid_{i}_{j}"

环形阵列:

import bpy
import math

count = 12
radius = 5

for i in range(count):
    angle = (2 * math.pi * i) / count
    x = radius * math.cos(angle)
    y = radius * math.sin(angle)
    bpy.ops.mesh.primitive_cylinder_add(radius=0.3, depth=2, location=(x, y, 0))
    obj = bpy.context.active_object
    obj.rotation_euler.z = angle

从高度图生成地形:

import bpy
import bmesh
import math
import random

size = 20
res = 50

bm = bmesh.new()
verts = []
for i in range(res):
    row = []
    for j in range(res):
        x = (i / res - 0.5) * size
        y = (j / res - 0.5) * size
        z = math.sin(x * 0.5) * math.cos(y * 0.5) * 2 + random.uniform(-0.2, 0.2)
        row.append(bm.verts.new((x, y, z)))
    verts.append(row)

for i in range(res - 1):
    for j in range(res - 1):
        bm.faces.new((verts[i][j], verts[i+1][j], verts[i+1][j+1], verts[i][j+1]))

mesh = bpy.data.meshes.new("Terrain")
bm.to_mesh(mesh)
bm.free()

obj = bpy.data.objects.new("Terrain", mesh)
bpy.context.collection.objects.link(obj)

# Smooth the terrain
sub = obj.modifiers.new("Smooth", 'SUBSURF')
sub.levels = 1
6. 为面分配材质
import bpy
import bmesh

obj = bpy.context.active_object

# Create materials
mat_red = bpy.data.materials.new("Red")
mat_red.diffuse_color = (1, 0, 0, 1)
mat_blue = bpy.data.materials.new("Blue")
mat_blue.diffuse_color = (0, 0, 1, 1)

obj.data.materials.append(mat_red)   # index 0
obj.data.materials.append(mat_blue)  # index 1

# Assign by face index
for i, poly in enumerate(obj.data.polygons):
    poly.material_index = 0 if i % 2 == 0 else 1

示例

示例 1:参数化楼梯

用户请求:“生成一个 20 级的螺旋楼梯”

import bpy
import math

def create_spiral_staircase(steps=20, radius=3, height=6, step_width=1.5):
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete()

    step_height = height / steps
    angle_per_step = (2 * math.pi) / steps

    for i in range(steps):
        angle = i * angle_per_step
        x = radius * math.cos(angle)
        y = radius * math.sin(angle)
        z = i * step_height

        bpy.ops.mesh.primitive_cube_add(
            size=1,
            location=(x, y, z),
            scale=(step_width, 0.4, step_height * 0.8)
        )
        step = bpy.context.active_object
        step.rotation_euler.z = angle
        step.name = f"Step_{i+1:02d}"

    # Add central column
    bpy.ops.mesh.primitive_cylinder_add(
        radius=0.2, depth=height, location=(0, 0, height / 2)
    )
    bpy.context.active_object.name = "CentralColumn"

create_spiral_staircase(steps=20)
bpy.ops.wm.save_as_mainfile(filepath="/tmp/staircase.blend")
示例 2:蜂窝面板

用户请求:“创建一个平面的蜂窝图案面板”

import bpy
import bmesh
import math

def create_hexagon(bm, cx, cy, radius):
    verts = []
    for i in range(6):
        angle = math.radians(60 * i + 30)
        x = cx + radius * math.cos(angle)
        y = cy + radius * math.sin(angle)
        verts.append(bm.verts.new((x, y, 0)))
    bm.faces.new(verts)

radius = 0.5
rows, cols = 8, 10
bm = bmesh.new()

for row in range(rows):
    for col in range(cols):
        cx = col * radius * 1.75
        cy = row * radius * 1.52
        if col % 2 == 1:
            cy += radius * 0.76
        create_hexagon(bm, cx, cy, radius * 0.9)

mesh = bpy.data.meshes.new("Honeycomb")
bm.to_mesh(mesh)
bm.free()

obj = bpy.data.objects.new("Honeycomb", mesh)
bpy.context.collection.objects.link(obj)

# Add thickness
solid = obj.modifiers.new("Solidify", 'SOLIDIFY')
solid.thickness = 0.1

指南

  • 对于简单的静态网格,使用 from_pydata()。当你需要通过挤出、细分或逐面操作等操作构建几何体时,使用 bmesh。
  • 在 from_pydata() 之后务必调用 mesh.update(),在 bmesh 操作之后务必调用 bm.free()。
  • 通过 bpy.ops.object.modifier_apply() 应用修改器时,确保对象处于活动且选中状态。
  • 对于大型程序化网格(10k+ 面),优先使用 bmesh 而非反复调用 bpy.ops —— 由于运算符每次调用都有开销,bmesh 明显更快。
  • 使用 bpy.context.collection.objects.link(obj) 将新对象链接到集合 —— 未链接到任何集合的对象不会出现在场景中。
  • Blender 使用 Z 轴向上的坐标系。从 Y 轴向上的系统(大多数游戏引擎)导入时请记住这一点。
  • 对于平滑着色:bpy.ops.object.shade_smooth() 或设置每个面的 polygon.use_smooth = True。
  • 先用较小的数量测试程序化脚本,然后再扩大规模。一个带有细分修改器的 100x100 网格可能会让 Blender 卡死。

评论

支持 Markdown