【blender/python】階段生成スクリプト試作1 メモ
import bpy
import mathutils
# 既存のオブジェクトを削除
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)
# ========= パラメータ =========
step_width = 1.0 # 階段の幅(X方向)
step_height = 0.18 # 1段の高さ(Z方向)
step_depth = 0.28 # 1段の奥行(Y方向)
num_steps = 12 # 段数
board_thickness = 0.03 # 踏み板の厚み
rail_height = 0.9 # 手すり高さ
post_radius = 0.02 # 支柱半径
rail_radius = 0.03 # 手すり半径
post_spacing = 2 # 支柱を何段ごとに置くか
# =============================
# --- 階段(踏み板+蹴込み板) ---
for i in range(num_steps):
y = i * step_depth
z = i * step_height
# 踏み板
bpy.ops.mesh.primitive_cube_add(
size=2, # ★ 幅の扱いをシンプルに
location=(0, y, z + board_thickness/2)
)
step = bpy.context.active_object
step.scale = (step_width/2, step_depth/2, board_thickness/2)
# 蹴込み板(立ち板)
if i > 0:
bpy.ops.mesh.primitive_cube_add(
size=2,
location=(0, y - step_depth/2 + 0.01, z - step_height/2 + board_thickness/2)
)
riser = bpy.context.active_object
riser.scale = (step_width/2, 0.01, step_height/2)
# --- 手すり支柱 ---
posts = []
for i in range(0, num_steps+1, post_spacing):
y = i * step_depth
z = i * step_height
for side in (-1, 1):
x = side * (step_width/2)
bpy.ops.mesh.primitive_cylinder_add(
radius=post_radius,
depth=rail_height,
location=(x, y, z + rail_height/2)
)
posts.append(bpy.context.active_object)
# --- 手すり(左右) ---
def create_rail(side):
x = side * (step_width/2)
start = mathutils.Vector((x, 0, rail_height))
end = mathutils.Vector((x, num_steps*step_depth, num_steps*step_height + rail_height))
vec = end - start
length = vec.length
mid = (start + end) / 2
bpy.ops.mesh.primitive_cylinder_add(
radius=rail_radius,
depth=length,
location=mid
)
rail = bpy.context.active_object
rail.rotation_mode = 'QUATERNION'
rail.rotation_quaternion = vec.to_track_quat('Z', 'Y')
create_rail(1)
create_rail(-1)
import bpy
import mathutils
# 既存のオブジェクトを削除
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)
# ========= パラメータ =========
step_width = 1.2 # 階段の幅
step_height = 0.18
step_depth = 0.28
num_steps = 10
board_thickness = 0.04
rail_height = 1.0 # 手すり高さ
# =============================
# --- 踏み板と蹴込み板 ---
for i in range(num_steps):
y = i * step_depth
z = i * step_height
# 踏み板
bpy.ops.mesh.primitive_cube_add(size=2, location=(0, y, z + board_thickness/2))
step = bpy.context.active_object
step.scale = (step_width/2, step_depth/2, board_thickness/2)
# 蹴込み板
if i > 0:
bpy.ops.mesh.primitive_cube_add(size=2, location=(0, y - step_depth/2, z - step_height/2 + board_thickness/2))
riser = bpy.context.active_object
riser.scale = (step_width/2, 0.01, step_height/2)
# --- バラスター(装飾支柱) ---
for i in range(num_steps+1):
y = i * step_depth
z = i * step_height
for side in (-1, 1):
x = side * (step_width/2 - 0.05)
# 胴体(踏み板から手すりまで)
bpy.ops.mesh.primitive_cylinder_add(
radius=0.025,
depth=rail_height,
location=(x, y, z + rail_height/2)
)
body = bpy.context.active_object
# 下の膨らみ
bpy.ops.mesh.primitive_uv_sphere_add(radius=0.05, location=(x, y, z + 0.05))
bottom_sphere = bpy.context.active_object
# 中間の膨らみ(くびれ感)
bpy.ops.mesh.primitive_uv_sphere_add(radius=0.04, location=(x, y, z + rail_height/2))
mid_sphere = bpy.context.active_object
# 上の膨らみ ← ★追加
bpy.ops.mesh.primitive_uv_sphere_add(radius=0.05, location=(x, y, z + rail_height - 0.05))
top_sphere = bpy.context.active_object
# --- 親柱(太い支柱) ---
for side in (-1, 1):
for y, z in [(0, 0), (num_steps*step_depth, num_steps*step_height)]:
x = side * (step_width/2 - 0.05)
bpy.ops.mesh.primitive_cube_add(size=2, location=(x, y, z + rail_height/2))
post = bpy.context.active_object
post.scale = (0.1, 0.1, rail_height/2)
# --- 手すり ---
def create_rail(side):
x = side * (step_width/2 - 0.05)
start = mathutils.Vector((x, 0, rail_height))
end = mathutils.Vector((x, num_steps*step_depth, num_steps*step_height + rail_height))
vec = end - start
length = vec.length
mid = (start + end) / 2
bpy.ops.mesh.primitive_cylinder_add(radius=0.05, depth=length, location=mid)
rail = bpy.context.active_object
rail.rotation_mode = 'QUATERNION'
rail.rotation_quaternion = vec.to_track_quat('Z', 'Y')
create_rail(1)
create_rail(-1)
import bpy
import mathutils
# 例: 外部ファイルのパス(必要に応じて変更)
filepath = "任意のデザインの柱のblenderファイルへのパス.blend"
directory = filepath + "/Object/"
object_name = "立方体" # .blend 内の柱のオブジェクト名
step_width = 1.2
step_height = 0.18
step_depth = 0.28
num_steps = 10
board_thickness = 0.04
rail_height = 1.0
# =======================
# --- シーンをクリア ---
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)
# --- 読み込み ---
bpy.ops.wm.append(
filepath=directory + object_name,
directory=directory,
filename=object_name
)
template = bpy.data.objects[object_name]
# --- ワールド座標のバウンディングボックスで高さを取得 ---
bpy.context.view_layer.update()
world_bb = [template.matrix_world @ mathutils.Vector(corner) for corner in template.bound_box]
z_min = min(v.z for v in world_bb)
z_max = max(v.z for v in world_bb)
original_height = z_max - z_min
# --- 一様スケール(既存scaleを考慮) ---
if original_height > 0:
scale_factor = rail_height / original_height
template.scale = tuple(s * scale_factor for s in template.scale)
bpy.context.view_layer.update()
print(f"バラスター高さ {original_height:.3f} → {rail_height:.3f}")
else:
scale_factor = 1.0
# --- 階段(踏み板+蹴込み板) ---
for i in range(num_steps):
y = i * step_depth
z = i * step_height
bpy.ops.mesh.primitive_cube_add(size=2, location=(0, y, z + board_thickness/2))
step = bpy.context.active_object
step.scale = (step_width/2, step_depth/2, board_thickness/2)
if i > 0:
bpy.ops.mesh.primitive_cube_add(size=2, location=(0, y - step_depth/2, z - step_height/2 + board_thickness/2))
riser = bpy.context.active_object
riser.scale = (step_width/2, 0.01, step_height/2)
# --- バラスター配置 ---
for i in range(num_steps+1):
y = i * step_depth
z = i * step_height
for side in (-1, 1):
x = side * (step_width/2 - 0.05)
baluster = template.copy()
baluster.data = template.data.copy()
bpy.context.collection.objects.link(baluster)
bpy.context.view_layer.update()
# コピー後の底面を取得
bb_world = [baluster.matrix_world @ mathutils.Vector(corner) for corner in baluster.bound_box]
z_min_copy = min(v.z for v in bb_world)
# 踏み板上に底面が来るよう補正
baluster.location = (x, y, z - z_min_copy)
# --- テンプレート削除 ---
bpy.data.objects.remove(template, do_unlink=True)
# --- 親柱 ---
for side in (-1, 1):
for y, z in [(0, 0), (num_steps*step_depth, num_steps*step_height)]:
x = side * (step_width/2 - 0.05)
bpy.ops.mesh.primitive_cube_add(size=2, location=(x, y, z + rail_height/2))
post = bpy.context.active_object
post.scale = (0.1, 0.1, rail_height/2)
# --- 手すり ---
def create_rail(side):
x = side * (step_width/2 - 0.05)
start = mathutils.Vector((x, 0, rail_height))
end = mathutils.Vector((x, num_steps*step_depth, num_steps*step_height + rail_height))
vec = end - start
length = vec.length
mid = (start + end) / 2
bpy.ops.mesh.primitive_cylinder_add(radius=0.05, depth=length, location=mid)
rail = bpy.context.active_object
rail.rotation_mode = 'QUATERNION'
rail.rotation_quaternion = vec.to_track_quat('Z', 'Y')
create_rail(1)
create_rail(-1)
def create_flat_rail(side, rail_width=0.2, rail_thickness=0.1, bevel=0.2): x = side * (step_width/2 - 0.05) start = mathutils.Vector((x, 0, rail_height)) end = mathutils.Vector((x, num_steps*step_depth, num_steps*step_height + rail_height)) vec = end - start length = vec.length mid = (start + end) / 2 # Cube追加 bpy.ops.mesh.primitive_cube_add(size=2, location=mid) rail = bpy.context.active_object # 形を整える rail.scale = (rail_width/2, length/2, rail_thickness/2) rail.rotation_mode = 'QUATERNION' rail.rotation_quaternion = vec.to_track_quat('Y', 'Z') # ベベルモディファイア mod = rail.modifiers.new(name="Bevel", type='BEVEL') mod.width = bevel mod.segments = 2 mod.profile = 0.7 mod.limit_method = 'NONE' # ← 制限なしで全エッジをベベル # スムースシェーディング bpy.ops.object.shade_smooth() # 実行(左右2本) create_flat_rail(1) create_flat_rail(-1)
コメント
コメントを投稿