
Blenderには、「Pythonコーディング」というプログラミング実行機能があります。
感覚的に3Dをモデリングしたり、内容のセットを行うのではなく、固定値や繰り返し作業を効率的にできるようになります。
この機能を使って、AIにモデリングをやらせてみて、どのくらいゲーム制作の役に立つかを検証してみたいと思います。
ChatGPTでPythonモデリング
プロンプトに次のような内容を書いて返答をもらいました。
ゲーム制作で使うための家のモデリングを
Blenderのpythonコードで出力して。
AIの返答
- まずは**「田舎村に置く小さな家」**を、BlenderのPythonで自動生成する形にしてみました。
壁
木製の柱・梁
ドア
十字格子の窓
切妻屋根
煙突
石の基礎
玄関の階段
まで含めています。
Blender用Pythonスクリプトをダウンロード(.pyのソースコードを表示)
pyコード
import bpy
import math
from mathutils import Vector
# ============================================================
# 田舎村の小さな家 - Blender Python Generator
# Blender 4.x 想定
# 実行すると現在のシーンをクリアして家を1軒生成します。
# ============================================================
# -----------------------------
# パラメータ
# -----------------------------
HOUSE_W = 4.0
HOUSE_D = 3.6
WALL_H = 2.4
FOUNDATION_H = 0.25
ROOF_OVERHANG = 0.35
ROOF_H = 1.35
WALL_THICK = 0.16
ROOF_THICK = 0.18
# -----------------------------
# マテリアル
# -----------------------------
def mat(name, color, roughness=0.8):
m = bpy.data.materials.new(name)
m.diffuse_color = (*color, 1.0)
m.roughness = roughness
return m
MAT_WALL = mat("Wall_Warm_Plaster", (0.62, 0.46, 0.30))
MAT_WALL_LIGHT = mat("Wall_Light", (0.72, 0.56, 0.38))
MAT_WOOD = mat("Wood_Dark", (0.25, 0.12, 0.055))
MAT_WOOD_LIGHT = mat("Wood_Light", (0.42, 0.22, 0.09))
MAT_ROOF = mat("Roof_Terracotta", (0.30, 0.10, 0.055))
MAT_ROOF_LIGHT = mat("Roof_Edge", (0.40, 0.16, 0.08))
MAT_GLASS = mat("Window_Glass", (0.18, 0.32, 0.35), 0.25)
MAT_STONE = mat("Foundation_Stone", (0.25, 0.24, 0.20))
MAT_METAL = mat("Metal", (0.16, 0.15, 0.12))
MAT_CHIMNEY = mat("Chimney", (0.35, 0.18, 0.12))
# -----------------------------
# 基本関数
# -----------------------------
def cube(name, loc, scale, material, bevel=0.0):
bpy.ops.mesh.primitive_cube_add(location=loc)
obj = bpy.context.object
obj.name = name
obj.scale = (scale[0] / 2, scale[1] / 2, scale[2] / 2)
bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
if material:
obj.data.materials.append(material)
if bevel > 0:
mod = obj.modifiers.new("Soft_Edges", "BEVEL")
mod.width = bevel
mod.segments = 2
return obj
def roof_panel(name, y, angle):
# 屋根片を長方形板として作成
length = math.sqrt((HOUSE_D + ROOF_OVERHANG * 2) ** 2 + ROOF_H ** 2)
z = WALL_H + ROOF_H / 2
obj = cube(
name,
(0, y, z),
(HOUSE_W + ROOF_OVERHANG * 2, length, ROOF_THICK),
MAT_ROOF,
bevel=0.03
)
obj.rotation_euler[0] = angle
return obj
def cylinder(name, loc, radius, depth, material, vertices=8):
bpy.ops.mesh.primitive_cylinder_add(
vertices=vertices,
radius=radius,
depth=depth,
location=loc
)
obj = bpy.context.object
obj.name = name
obj.data.materials.append(material)
return obj
# -----------------------------
# シーン初期化
# -----------------------------
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=False)
# -----------------------------
# 土台
# -----------------------------
cube(
"Foundation",
(0, 0, FOUNDATION_H / 2),
(HOUSE_W + 0.18, HOUSE_D + 0.18, FOUNDATION_H),
MAT_STONE,
bevel=0.05
)
# -----------------------------
# 壁
# -----------------------------
z_wall = FOUNDATION_H + WALL_H / 2
# 正面・背面
cube(
"Wall_Front",
(0, -HOUSE_D / 2, z_wall),
(HOUSE_W, WALL_THICK, WALL_H),
MAT_WALL,
bevel=0.025
)
cube(
"Wall_Back",
(0, HOUSE_D / 2, z_wall),
(HOUSE_W, WALL_THICK, WALL_H),
MAT_WALL,
bevel=0.025
)
# 左右
cube(
"Wall_Left",
(-HOUSE_W / 2, 0, z_wall),
(WALL_THICK, HOUSE_D, WALL_H),
MAT_WALL,
bevel=0.025
)
cube(
"Wall_Right",
(HOUSE_W / 2, 0, z_wall),
(WALL_THICK, HOUSE_D, WALL_H),
MAT_WALL,
bevel=0.025
)
# -----------------------------
# 柱・梁
# -----------------------------
for x in (-HOUSE_W / 2 + 0.12, HOUSE_W / 2 - 0.12):
cube(
"Front_Post",
(x, -HOUSE_D / 2 - 0.03, FOUNDATION_H + WALL_H / 2),
(0.18, 0.22, WALL_H),
MAT_WOOD,
bevel=0.025
)
cube(
"Front_Beam",
(0, -HOUSE_D / 2 - 0.04, FOUNDATION_H + WALL_H - 0.18),
(HOUSE_W, 0.22, 0.18),
MAT_WOOD,
bevel=0.025
)
# -----------------------------
# ドア
# -----------------------------
door_w = 0.85
door_h = 1.65
cube(
"Door",
(0, -HOUSE_D / 2 - 0.12, FOUNDATION_H + door_h / 2),
(door_w, 0.12, door_h),
MAT_WOOD_LIGHT,
bevel=0.025
)
# ドアの板
for x in (-0.25, 0.0, 0.25):
cube(
"Door_Plank",
(x, -HOUSE_D / 2 - 0.19, FOUNDATION_H + door_h / 2),
(0.035, 0.025, door_h - 0.08),
MAT_WOOD,
)
# ドアノブ
cylinder(
"Door_Handle",
(0.25, -HOUSE_D / 2 - 0.23, FOUNDATION_H + 0.82),
0.055,
0.04,
MAT_METAL,
8
).rotation_euler[0] = math.radians(90)
# -----------------------------
# 窓
# -----------------------------
def make_window(x, y, z):
frame_w = 0.95
frame_h = 0.85
cube(
"Window_Glass",
(x, y, z),
(frame_w, 0.08, frame_h),
MAT_GLASS,
bevel=0.015
)
# 縦枠
cube("Window_Frame_L", (x - frame_w/2, y - 0.06, z),
(0.10, 0.13, frame_h + 0.10), MAT_WOOD)
cube("Window_Frame_R", (x + frame_w/2, y - 0.06, z),
(0.10, 0.13, frame_h + 0.10), MAT_WOOD)
# 横枠
cube("Window_Frame_T", (x, y - 0.06, z + frame_h/2),
(frame_w + 0.10, 0.13, 0.10), MAT_WOOD)
cube("Window_Frame_B", (x, y - 0.06, z - frame_h/2),
(frame_w + 0.10, 0.13, 0.10), MAT_WOOD)
# 十字桟
cube("Window_Mullion_V", (x, y - 0.085, z),
(0.07, 0.04, frame_h), MAT_WOOD)
cube("Window_Mullion_H", (x, y - 0.085, z),
(frame_w, 0.04, 0.07), MAT_WOOD)
# 正面の左右窓
make_window(-1.25, -HOUSE_D / 2 - 0.08, FOUNDATION_H + 1.35)
make_window(1.25, -HOUSE_D / 2 - 0.08, FOUNDATION_H + 1.35)
# -----------------------------
# 屋根
# -----------------------------
roof_angle = math.atan2(ROOF_H, HOUSE_D / 2 + ROOF_OVERHANG)
# 屋根の左右の傾斜
left_roof = roof_panel("Roof_Left", -HOUSE_D / 4, -roof_angle)
right_roof = roof_panel("Roof_Right", HOUSE_D / 4, roof_angle)
# 屋根位置補正
left_roof.location.y = -HOUSE_D / 4
right_roof.location.y = HOUSE_D / 4
# 屋根の棟木
cube(
"Roof_Ridge",
(0, 0, WALL_H + ROOF_H),
(HOUSE_W + ROOF_OVERHANG * 2, 0.16, 0.16),
MAT_ROOF_LIGHT,
bevel=0.025
)
# -----------------------------
# 煙突
# -----------------------------
chimney_x = HOUSE_W * 0.25
chimney_y = HOUSE_D * 0.10
cube(
"Chimney",
(chimney_x, chimney_y, WALL_H + ROOF_H * 0.72),
(0.42, 0.42, 1.05),
MAT_CHIMNEY,
bevel=0.025
)
cube(
"Chimney_Cap",
(chimney_x, chimney_y, WALL_H + ROOF_H * 0.72 + 0.55),
(0.52, 0.52, 0.12),
MAT_WOOD_DARK if "MAT_WOOD_DARK" in globals() else MAT_WOOD,
bevel=0.02
)
# -----------------------------
# 小さな階段
# -----------------------------
cube(
"Step_1",
(0, -HOUSE_D / 2 - 0.30, FOUNDATION_H * 0.55),
(1.15, 0.45, 0.18),
MAT_STONE,
bevel=0.04
)
cube(
"Step_2",
(0, -HOUSE_D / 2 - 0.55, FOUNDATION_H * 0.30),
(1.35, 0.45, 0.12),
MAT_STONE,
bevel=0.04
)
# -----------------------------
# 原点を家の中央・地面に設定
# -----------------------------
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='BOUNDS')
# コレクション
house_collection = bpy.data.collections.new("HOUSE")
bpy.context.scene.collection.children.link(house_collection)
for obj in list(bpy.context.scene.objects):
if obj.type == 'MESH':
for collection in list(obj.users_collection):
collection.objects.unlink(obj)
house_collection.objects.link(obj)
# -----------------------------
# 表示設定
# -----------------------------
for obj in house_collection.objects:
obj.select_set(False)
# 家全体を選択
for obj in house_collection.objects:
obj.select_set(True)
# -----------------------------
# 保存
# -----------------------------
print("====================================")
print("田舎村の家を生成しました")
print("コレクション: HOUSE")
print("====================================")
Blenderでpyを実行
Blenderで、「Scripting」モードに切り替えて、「+ New」をクリックします。
表示されたエディタに、AIが作ったプログラミングデータをコピペします。
そのまま、「Run Script」ボタン(▶︎)をクリックすると、モデルデータが構築されます。
出来上がったモデルの評価
出来上がりを詳しくみてみましょう。
「家」という感じですが、特におしゃれでもなければ、大した特徴もありません。
屋根のつながり部分の壁に、無意味な線が入っていますね。
これは、壁部分の四角と、屋根部分の三角のつなぎめのようです。
下から見上げてみると、屋根の傾斜が、沿っている壁と合っていなくて、隙間ができていました。
横の窓も、柱にめり込んでいますね。
全体的に、柱や壁、基礎部分、すべてのオブジェクトに、ベベル処理がされているので、少しもっさりとした雰囲気になっています。
どうやら、かなり手直しが必要な仕上がりということがわかりました。
ただ、プロンプトでしっかりと書いて、なるべく手直しを減らすということもできるかもしれません。
あとがき
今回、AIに作ってもらったpythonデータをみると、Blenderのver4用で作られていました。
プロンプトでver5を指定した方がいいかもしれませんね。
モデリングする上では、さほど違いはないかもしれませんが、実行環境は適切に伝えておいた方が、問題も少なくなりますからね。
とにかく、ベースモデリングをやってもらえるのは、少し助かりはしますが、丸投げできるクオリティではなさそうということがわかりました。
個人的には、もっとローポリで、テクスチャなどを貼り付けるだけでもいいかと思っているので、やはり3Dモデラーの仕事は、まだAIには難しいという領域なんですね。
きっとそのうちに、AIも成長するというのは、誰もが思うかもしれませんが、今この瞬間でできているかどうかの評価をすることが大事です。
他のジャンルでも、全く同じことが言えますけどね。
0 件のコメント:
コメントを投稿