背景と目的
近年、テキストから画像・動画を一発生成する生成AIが台頭し、従来の3DCGは「わざわざモデリングしなくてもいいのでは?」という空気さえ漂っています。
しかし発想を変えれば、AIを使って3Dソフトを操作すること自体が新しい体験になります。
今回は Blender MCP × LM Studio × gpt-oss というローカル環境を組み合わせ、自然語だけで3Dシーンを構築し、最後はカメラ周回アニメまで作る実験をしました。
筆者はBlenderで昔、ドミノ倒しの物理演算を試した程度の初心者ですが、「もし自然語で自動化できたら面白そうだ」と思い立ったのが出発点です。
環境準備
- Blender に MCP (Model Context Protocol) を導入
- LM Studio で gpt-oss を起動し、MCP プラグイン経由で Blender と接続
- 以後、自然語を投げると LLM が Python コードを生成し、Blender 内で実行される
(詳細なセットアップ手順は末尾の付録にまとめています)
自然語でシーン構築
最初の試みは「25個のキューブを並べて3層に複製」。
自然語で次のように指示します:
- 1辺2のキューブを 5×5 に並べ、隙間は1
- これをZ方向に3層複製(層間隔3)
- 各層を Floor1〜3 のコレクションにまとめる
さらに「全キューブにランダムな高彩度マテリアルを割り当てよ」と続けると、色とりどりのオブジェクトが並びます。
この時のコツは「RGBランダム」ではなく「HSV指定」。Hueをランダム、Saturationを0.9〜1.0、Valueを0.8〜1.0と指定すると鮮やかな色になります。
カメラやライトも自動配置。ここまで自然語で一気にシーンが整いました。
ハマりどころ(罠と対処)
もちろん順風満帆ではありません。
- 真っ暗事件
F11とF12を取り違え、「レンダーしても真っ暗」に。F12が正解です。 - ライト逆向き事件
Blenderのライト正面は -Z方向。
「原点を向けろ」と自然語で指示したのに、なぜか反対を向く──これは仕様でした。解決策は Track To 制約を使うこと。 - 床に埋まる事件
キューブの底面が床と干渉して真っ黒に。Z=-2 に床を置くことで回避。 - カラーマネジメント/Eevee設定
Cycles で重くなりすぎる、EEVEEで背景が透過になるなど、細かい調整も必要でした。 - 結構止まる
コンテキストの消費は大きいです。幸い、チャットを分割して作業は継続できます


アニメはPythonで安定化
「カメラを原点の周りに回し、常に原点を見続ける」──ここで自然語指示は限界に。
自然語では
- 「カメラ本体を回すのか?」
- 「親のEmptyを回すのか?」
- 「注視はTrack ToかDamped Trackか?」
と解釈が揺れて、安定しませんでした。
最終的には Python で一発解決:
- 原点に Empty「TrackTarget」を追加
- カメラに Damped Track 制約で Target を注視
- もう1つ Empty「OrbitPivot」を作ってカメラを子にし、Z軸で360°回転アニメーション
- フレーム範囲 1〜120、補間は線形
- 出力は FFmpeg / MPEG-4 / H.264
これで滑らかなカメラ周回動画が完成。ブログに貼れる映像ができました。
速度・運用の本音
ここで気づいたのが 速度の壁。
- ローカル gpt-oss では、25キューブ3層+マテリアル付与の処理に 約13分。しかも7回に分割してコードを投げる挙動。
- 対して GPT-5 なら Pythonコードを即座に生成してくれる。コードをローカルで実行すれば、速度も安定性も圧倒的。
結論:
「課金が怖い勢」も GPT-5でコードだけ生成 → ローカルで実行が最速で現実的。
MCPを使って「自然語だけで完結」を狙うと時間を浪費する一方で、シーン生成のアイデア出しや数式ベース配置には使える、と言えます。
Gemma 3 の試行錯誤ループ
参考までに、Gemma 3 でも試しました。学習済みでできると本人も言っていました。
You
あなたは、この機能を使って、シーンを行使くするコードを生成できますか?
google/gemma-3n-e4b
はい、可能です。どんなシーンを作成したいのか教えていただけますでしょうか? 具体的に指示していただければ、必要な Python コードを生成します。
面白いことに「自分で出したコードを否定・修正して再実行する」ループに陥りがち。
例:Cube が存在しないのに参照 → エラー → 「修正版コード」を提案 → 再実行…の繰り返し。
結果と所感
自然語で「ここまで」できるのは面白い
ただし仕上げはやはり Python が安定
gpt-oss は「動くが遅い」、GPT-5 は「速くて安定」
3DCGと生成AIは競合ではなく、「3DCG × 生成AI」として組み合わせると面白い未来が見える
付録:セットアップとプロンプト集
Blender MCP の導入
Blender 公式アドオンから MCP (Model Context Protocol) を有効化
「編集 → プリファレンス → アドオン」から MCP を検索し、チェックを入れる
有効化後、MCP が待ち受けできるようになる

LM Studio 側の設定
LM Studio に gpt-oss をロード(ローカル LLM 環境)
MCP プラグインを有効にして Blender と接続

以降、自然語プロンプトを投げると Python コードが生成され、Blender 内で実行される
成功した自然語プロンプト例
紆余曲折の上、動くプロンプトが作れました。
シーン生成
新規シーンにしてください。
1辺2のキューブを5×5で並べ、隙間は1にしてください。
原点中心に配置し、これを「BaseCubes」コレクションにまとめてください。
この25個のキューブをZ方向に複製して3層にし、層間隔は3にしてください。
各層を Floor1, Floor2, Floor3 というコレクションに分けてください。
BaseCubes は不要なら削除してください。
マテリアル付与
すべての Floor コレクションのキューブに高彩度ランダム色のマテリアルを割り当て直してください。
- 既存の Principled BSDF ノードを再利用してください。
- Base Color は HSV でランダムにしてください。
Hue = 0〜1、Saturation = 0.9〜1.0、Value = 0.8〜1.0
- Metallic = 0.0、Roughness = 0.4 にしてください。
- 各キューブにはユニークなマテリアルを割り当ててください。
カメラとライト
カメラを追加してください。
位置は (25, -25, 20)、原点を向け、焦点距離は28mmにしてください。
このカメラをアクティブにしてください。
スポットライトを3つ追加してください。
Spot.001: 位置 (15, -10, 10)、強さ 5000、スポットサイズ 65°、ブレンド0.35、原点を向く。
Spot.002: 位置 (-15, -10, 8)、強さ 2500、スポットサイズ 65°、ブレンド0.35、原点を向く。
Spot.003: 位置 (0, 15, 15)、強さ 7000、スポットサイズ 60°、ブレンド0.35、原点を向く。
Eevee 設定
レンダーエンジンを EEVEE にしてください。
Ambient Occlusion と Bloom を有効にしてください。
ワールド背景色を #202020 にしてください。
最終的に使った Python コード(カメラ周回アニメ)
import bpy, math
scene = bpy.context.scene
scene.frame_start = 1
scene.frame_end = 120
# カメラ取得または作成
cam = scene.camera
if cam is None:
bpy.ops.object.camera_add(location=(25,-25,20))
cam = bpy.context.active_object
scene.camera = cam
cam.rotation_mode = 'XYZ'
# 原点ターゲット
target = bpy.data.objects.get("TrackTarget")
if target is None:
bpy.ops.object.empty_add(type='PLAIN_AXES', location=(0,0,0))
target = bpy.context.active_object
target.name = "TrackTarget"
# カメラに注視制約
if not any(c.type == 'DAMPED_TRACK' for c in cam.constraints):
ct = cam.constraints.new('DAMPED_TRACK')
ct.target = target
ct.track_axis = 'TRACK_NEGATIVE_Z'
ct.influence = 1.0
# 周回用ピボット
pivot = bpy.data.objects.get("OrbitPivot")
if pivot is None:
bpy.ops.object.empty_add(type='PLAIN_AXES', location=(0,0,0))
pivot = bpy.context.active_object
pivot.name = "OrbitPivot"
# 親子付け
cam.parent = pivot
cam.matrix_parent_inverse = pivot.matrix_world.inverted()
# キーフレーム設定
pivot.rotation_mode = 'XYZ'
pivot.keyframe_insert("rotation_euler", frame=scene.frame_start)
pivot.rotation_euler.z = 2*math.pi
pivot.keyframe_insert("rotation_euler", frame=scene.frame_end)
# 線形補間
for fc in pivot.animation_data.action.fcurves:
for kp in fc.keyframe_points:
kp.interpolation = 'LINEAR'
# 出力設定
scene.render.filepath = "//camera_orbit.mp4"
scene.render.image_settings.file_format = 'FFMPEG'
scene.render.ffmpeg.format = 'MPEG4'
scene.render.ffmpeg.codec = 'H264'
scene.render.resolution_x = 1920
scene.render.resolution_y = 1080
scene.render.fps = 24
print("カメラ周回アニメ設定完了")
運用Tips:まず軽いpingでMCPの生存確認→本命リクエスト
MCP は死活監視が弱い。軽いping(例:シーン一覧取得)を先に投げ、応答確認してから本命リクエストを送ると安定。
繰り返しリクエストを投げると応答が途切れる場合があるので、長い処理はPython一発コードにまとめて実行した方が良い。
「自然語でのお膳立て」「Pythonでの仕上げ」の役割分担がベストバランス。


