blender-3d-modeling について
BlenderのPython APIでプロシージャルな3D形状を作成するスキルです。メッシュ構築、bmesh編集、モディファイア、カーブなどを扱い、コードからモデルを作る制作者や技術者向けです。
主な機能
- 01頂点と面のデータからメッシュを構築
- 02bmeshによる形状編集
- 03Pythonでモディファイアを適用
- 04カーブとサーフェスの生成
- 05パラメトリックパターンや地形の作成
- 06メッシュ面へのマテリアル割り当て
活用シーン
- 01パラメトリックな階段の生成
- 02ハニカムパネルの作成
- 03グリッドや円形のオブジェクト配列を構築
- 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()でモディファイアを適用する際は、オブジェクトがアクティブかつ選択されていることを確認してください。- 大規模なプロシージャルメッシュ(1 万面以上)では、
bpy.opsの繰り返し呼び出しよりも bmesh を優先してください。オペレーターには呼び出しごとのオーバーヘッドがあるため、bmesh の方が大幅に高速です。 - 新しいオブジェクトは
bpy.context.collection.objects.link(obj)でコレクションにリンクしてください。どのコレクションにもリンクされていないオブジェクトはシーンに表示されません。 - Blender は Z アップ座標系を使用します。Y アップ座標系(ほとんどのゲームエンジン)からインポートする際はこの点に注意してください。
- スムーズシェーディングの場合:
bpy.ops.object.shade_smooth()を使用するか、面ごとにpolygon.use_smooth = Trueを設定してください。 - プロシージャルスクリプトはまず少ない数でテストし、その後スケールアップしてください。細分化モディファイアを適用した 100x100 のグリッドは Blender をフリーズさせる可能性があります。
コメント
Markdown 対応