叫 coding agent 直接開 Blender:一行 CLI 把 3D 建模變成寫 Python
本文大綱
一句 prompt、2 分 39 秒,就有一張可編輯的 3D 場景
2026-09-05,Simon Willison 在他的 TIL 站上貼了一篇〈Using Blender with coding agents on macOS〉。做法簡單到有點反高潮:從 blender.org 裝好 Blender 桌面版,然後對 coding agent 說一句話——
Use the already install /Applications/Blender to render a scene of a pelican riding a bicycle
他用的是 ChatGPT macOS 應用程式裡的 Codex 模式、GPT-6 Astra(Medium)。2 分 39 秒後,agent 交出一張鵜鶘騎腳踏車的 3D render,外加一個能在 Blender 裡繼續拉的 .blend。接著他追加兩輪:OK add a background and a lot of flair(3 分 51 秒)、OK make it a whole lot better(5 分 59 秒),畫面從棚拍白底一路長成海邊木棧道的日落嘉年華——有海灘小屋、彩旗、氣球、遠方帆船。
這些時間、prompt、產物都在 Simon 的 TIL 和他開的 repo simonw/gpt-6-astra-blender-pelican-bicycle 裡,我沒有 macOS 機器可以照樣重跑,以下凡是他回報的數字我都會標明。
重點不是鵜鶘。重點是這個認知轉換:Blender 這種重度 GUI 工具,對 coding agent 來說根本不是 GUI 工具,而是「一個帶 Python API 的 CLI」。你不需要 MCP server、不需要裝外掛、不需要讓模型截圖點按鈕。這篇要講清楚它為什麼能通、怎麼一步步接起來,以及哪幾個坑會讓你的 agent 安靜地失敗。
為什麼這條路走得通
三件事剛好湊在一起:
- Blender 的功能全都掛在
bpy這個 Python API 底下。 GUI 只是 API 的一層皮——你在介面上點的每個按鈕,背後都有對應的bpy.ops.*或資料層操作。這代表「建模」在技術上等同於「寫 Python」。 - Blender 原生支援 headless。
--background不開視窗、--python直接餵一份腳本進去跑完就退出。這是給 render farm 用的老功能,agent 剛好白撿。 - Agent 最強的迴圈就是「寫程式 → 跑 → 讀結果 → 改程式」。 把 3D 建模轉譯成寫 Python,正好落在它最擅長的地帶。
反過來看 GUI 路線為什麼難:要 agent 用視覺點按 Blender 介面,每一步都得截圖、辨識面板、猜當下的選取狀態,錯一步很難回復,而且完全沒有 diff 可看。scene-as-code 則有版本控管、能重跑、能參數化、能交給另一個人接手。
這裡值得順帶對照另一條大家更熟的路線:Siddharth Ahuja 的 blender-mcp(ahujasid/blender-mcp)。它是一個 Blender 外掛加 MCP server,讓 Claude、Cursor 等客戶端透過 MCP 直接操作正在執行中的 Blender——能取得場景資訊、抓 viewport 截圖、拉 Poly Haven / Sketchfab 素材。這條路的優勢是「即時互動、看得到當下場景」;代價是要裝外掛、要開著 Blender、要維護連線,而且產出的操作不必然留下一份可重跑的腳本。
Simon 這條 CLI 路線則是另一個極端:零安裝、零連線、產物就是程式碼。

運作原理:一行指令就是整條 pipeline
整套機制的核心只有這一行(Simon 在 TIL 裡建議你直接把它寫進 prompt,省下模型自己摸索的時間):
Use Blender like this: /Applications/Blender.app/Contents/MacOS/Blender --background --python scene.py
拆開看:
/Applications/Blender.app/Contents/MacOS/Blender—— macOS 上.app包裡的真正執行檔。這是 macOS 特有的細節,也是為什麼這篇 TIL 標題要掛 macOS:agent 常常只知道有blender這個指令,卻不知道 Homebrew Cask 裝的桌面版沒有把它放進PATH。--background(等同-b)—— 不開 GUI、不建視窗,跑完就退出。--python scene.py—— 用 Blender 內建的那顆 Python 執行腳本。這點很關鍵:bpy不能用系統 Python 跑,你的 agent 如果習慣性打python scene.py會直接ModuleNotFoundError。
然後迴圈是這樣轉的:
- Agent 把場景寫成
work/scene.py——幾何、材質、燈光、相機、render 設定全部程式化。 - 用上面那行指令跑掉。
- 腳本裡先
bpy.ops.wm.save_as_mainfile()存.blend、再bpy.ops.render.render(write_still=True)出圖。順序很重要,理由下面講。 - Agent 把產出的 PNG 讀回來看(這是整套流程裡最容易被跳過、但決定成敗的一步)。
- 發現輪胎浮空、遠景被地板蓋住、主體出框——回到第 1 步改腳本。
四個產物角色分得很乾淨:.py 是唯一真相(可 diff、可重跑)、.blend 是給人接手的(設計師能直接開來拉)、.png 是給 agent 回讀做視覺 QA 的、終端輸出則是給 agent 判斷有沒有炸掉的。
從 Simon 的實作裡抄得到的具體招式
他把整個實驗開源了,work/pelican_scene.py、pelican_flair.py、pelican_final.py 三個版本都在 repo 裡。讀完那幾支腳本,有幾個模式值得直接抄進你自己的 prompt。
招式一:叫 agent 先寫 helper 函式,不要硬幹 bpy.ops
pelican_scene.py 開頭定義了六個小工具:mat() 建材質、ell() 放橢球、rod() 在兩點之間拉圓柱、path() 用貝茲曲線做管狀物、torus() 做輪胎、mesh() 用 from_pydata 直接造網格。之後整台腳踏車、整隻鵜鶘都是靠這六個函式組出來的。
其中 rod() 這招特別實用——把「從 A 點到 B 點拉一根管」變成一行:
def rod(name, a, b, r, material):
a, b = Vector(a), Vector(b)
d = b - a
bpy.ops.mesh.primitive_cylinder_add(
vertices=24, radius=r, depth=d.length, location=(a + b) / 2)
o = bpy.context.object
o.name = name
o.rotation_euler = d.to_track_quat('Z', 'Y').to_euler()
bevel = o.modifiers.new('Rounded edges', 'BEVEL')
bevel.width = r * .28
bevel.segments = 3
o.modifiers.new('Weighted normals', 'WEIGHTED_NORMAL')
return o
to_track_quat('Z','Y') 是把圓柱的 Z 軸對齊到方向向量的標準寫法。有了它,車架五根管就是五行 rod(...),輪輻是一個 28 次的 for loop。
可以照抄的 prompt 片段:
先在
work/建立一份helpers.py,定義mat / ell / rod / path / torus這幾個 primitive helper,之後所有場景腳本都 import 它。不要在主腳本裡重複貼bpy.ops.mesh.primitive_*_add的樣板碼。
招式二:render 設定當成 checklist 交給 agent
Simon 讓 Codex 產出的 skill 檔裡,把「收尾設定」寫成一段固定模板:
scene = bpy.context.scene
scene.render.engine = 'CYCLES'
scene.cycles.samples = 64
scene.cycles.use_denoising = True
scene.render.resolution_x = 1600
scene.render.resolution_y = 1200
scene.render.resolution_percentage = 100
scene.view_settings.view_transform = 'AgX'
scene.render.image_settings.file_format = 'PNG'
scene.render.filepath = str(output_dir / 'scene.png')
bpy.ops.wm.save_as_mainfile(filepath=str(output_dir / 'scene.blend'))
bpy.ops.render.render(write_still=True)
裡面有兩個判斷值得記住。第一,samples 的建議值:skill 裡寫預覽用 32–48、要出成品用 64–96,並開 denoising。Simon 的三個版本實際上就是 48 → 96 遞增(最終版 pelican_final.py 是 2000×1600、96 samples)。第二,view_transform = 'AgX'——這是 Blender 4.0 之後的預設色調映射,比舊的 Filmic 更不容易把高光燒白;agent 如果沿用網路上舊教學可能會設成 Filmic 或 Standard,畫面就會偏。
還有一句 skill 裡明講的提醒:「Do not assume GPU acceleration is configured.」 Cycles 預設走 CPU,你的 render 時間會比想像中長,這也是為什麼那三輪迭代要花 2–6 分鐘。
招式三:強制 agent 回讀渲染圖
這是整篇最重要的一招。Simon 讓 Codex 產出的 skill 裡有一句幾乎可以裱框的話:
A successfully saved render is not visual QA.
(render 成功存檔,不等於做過視覺檢查。)
Skill 裡列出的檢查清單非常具體,你可以直接複製進自己的 AGENTS.md 或 CLAUDE.md:
- 剪影對不對(smooth shading 救不了面數不夠的多邊形輪廓)
- 手有沒有真的握到握把、腳有沒有踩到踏板
- 有沒有零件浮空
- 主體有沒有被畫面裁到
- 陰影合不合理
- 背景細節到底有沒有出現在畫面裡(加了不等於看得到)
同一份 skill 還記了幾個他們真的踩過的坑:舊的攝影棚地板沒刪掉,結果把新加的沙灘和海洋整個蓋住;共面重疊的表面渲出黑帶(就是 z-fighting);正交相機配無限延伸的地平面根本不會有自然地平線,得另外放一片遠景天空背板才會有一條齊的水平線。
招式四:把「怎麼開 Blender」沉澱成 skill
Simon 最後一步是叫 Codex 用它內建的 skill-creating skill,把這次學到的東西打包:
Create a quick skill that describes how to use the currently installed /Application/Blender based on what you learned
產出的 SKILL.md frontmatter 長這樣:
---
name: blender-local
description: Build, edit, and render 3D scenes with the locally installed Blender on this Mac. Use when the user requests Blender work or an editable Blender scene.
---
之後他就用 Use your Blender Local skill to build this scene (attached image) 這種一句話 prompt 繼續玩。
這份 skill 的內容編排本身就是範本:已驗證的執行檔絕對路徑(skill 裡甚至特別註記是複數的 Applications,不是 /Application/Blender——因為第一次 prompt 打錯了)、工作流程(腳本放 work/、產物放交付目錄、要改舊場景就 bpy.ops.wm.open_mainfile(filepath=...) 而不是把舊腳本切一段出來跑)、已知的執行問題、視覺教訓。
這比「寫一份泛用的 Blender 教學」有價值得多,因為它記的是這台機器、這個版本、這次踩到的事。
幾個會讓 agent 安靜失敗的坑

坑一:Python 例外了,Blender 還是回傳 exit code 0
這是最陰的一個。Blender 官方手冊對 --python-exit-code 的說明是:設定一個 0–255 的 exit code,在 Python 拋出例外時用它退出(僅適用於命令列執行的腳本),設為零則關閉此功能。換句話說——預設是關的。
意思是:你的 agent 跑了腳本,腳本在第 40 行就炸了,Blender 印了 traceback 然後正常退出、exit code 0。Agent 一看回傳成功,就跑去回報「場景已完成」。這在 Blender 的 issue tracker 上是個老問題(#17647、#82494 都在談這件事),而且 issue 裡也提到 --python-exit-code 在某些情境(例如 unregister 階段的例外)仍然可能吞掉錯誤。
所以請把這行寫進你的 skill 或 AGENTS.md:
/Applications/Blender.app/Contents/MacOS/Blender \
--background \
--python-exit-code 1 \
--python work/scene.py
並且加一條規則:agent 必須確認 .png 和 .blend 兩個檔案真的被寫出來、mtime 是新的,才算完成。 光看 exit code 不夠。
坑二:引數是按順序執行的
Blender 手冊明說引數依給定順序執行。這代表 -o(輸出路徑)、-E(引擎)、-f / -a(觸發 render)之間的順序不能亂排——設定類的旗標必須排在觸發 render 的旗標之前,否則設定不會生效。同樣地,要載入既有 .blend 檔,檔名要放在最前面:
blender scene.blend --background --python-exit-code 1 --python tweak.py
如果要把參數傳給你的腳本,用 -- 分隔,之後的東西 Blender 一律不解析、原樣丟進 sys.argv:
blender -b --python-exit-code 1 --python render.py -- --samples 96 --out /tmp/out
腳本裡這樣撿:
import sys
argv = sys.argv[sys.argv.index('--') + 1:] if '--' in sys.argv else []
這招對 agent 特別有用——腳本寫一次,畫質預覽和最終出圖用同一份程式碼、不同參數,agent 不會為了改 samples 而去改壞別的東西。
坑三:sandbox 會讓 Blender 直接 segfault
Simon 的 skill 裡記了一筆很具體的環境問題:這個專案第一次在 sandbox 裡啟動 Blender 時,還沒跑到腳本就以 exit code 139 退出(139 = 128 + 11,SIGSEGV),並在系統暫存目錄留下 blender.crash.txt。改用「已核可的非 sandbox 執行途徑」重試就成功了。同時出現的 USD Arch_ValidateAssumptions 警告,skill 裡誠實註明「並未證實是根因」。
這件事對用 Claude Code / Codex 的人很實際:這類 agent 預設把指令跑在受限環境裡,而 Blender 啟動時會碰 GPU、audio、檔案系統一堆東西,很容易在 sandbox 下掛掉。如果你遇到「還沒印任何腳本輸出就 139」,先懷疑 sandbox,不要懷疑腳本。
(順帶一提,Blender 自己的 issue #126807 也有一個「用 bpy 模組跑 Cycles,渲染成功但 exit status 永遠是 139」的案例。exit 139 在 Blender 世界不算罕見,別讓 agent 拿它當「腳本有 bug」的證據。)
坑四:API 正在變
Simon 的 skill 記錄他那台機器上是 Blender 5.1.2(2026 年 9 月),並註明 Material.use_nodes 和 World.use_nodes 已經噴 deprecation 警告、仍可運作,但預期在 Blender 6 會改。
版本本身也在跑:目前 Blender 官方手冊掛的是 5.2 LTS,PyPI 上的 bpy 套件最新是 5.2.1(2026-08-25 發佈)、只支援 Python 3.13。這代表兩件事:一,模型訓練資料裡的 Blender API 寫法很可能過時;二,你應該讓 agent 每次開工前先跑一次版本檢查,而不是相信它記得的 API:
/Applications/Blender.app/Contents/MacOS/Blender --version
想出影片的話
Simon 在 TIL 開頭就提到模型「也能出影片——渲染一連串圖片再用 ffmpeg 合起來」。他的 repo 裡沒有影片範例,所以以下是這條路的標準做法,不是他實測過的流程:
在腳本裡設好 scene.frame_start / frame_end 和動畫 keyframe,然後:
blender -b scene.blend \
-o /tmp/frames/f_#### \
-F PNG \
-a
#### 會被換成補零的影格編號。接著:
ffmpeg -framerate 24 -i /tmp/frames/f_%04d.png \
-c:v libx264 -pix_fmt yuv420p -crf 18 out.mp4
為什麼不讓 Blender 直接輸出影片?因為分成兩段對 agent 友善得多:渲染中斷可以只補缺的影格、agent 可以抽幾張 frame 回讀做 QA、換 codec 不用重渲。這條原則跟前面「先存 .blend 再 render」是同一個思路——把長時間、易失敗的步驟切開,讓每一段都可以單獨重跑。
macOS 以外呢
TIL 標題掛 macOS,是因為那條 .app 執行檔路徑是 macOS 專屬的麻煩。換平台就換路徑:
- Linux:套件管理裝的通常
blender就在PATH上;Snap / Flatpak 或官方 tarball 則要指到解壓目錄下的blender。 - Windows:預設在
C:\Program Files\Blender Foundation\Blender <版本>\blender.exe。 - 完全不裝桌面版:
pip install bpy(現在是 5.2.1)把 Blender 當成 Python 模組用,官方 wheel 涵蓋 macOS ARM64、Linux x86-64(glibc 2.28+)、Windows x86-64 與 ARM64。這條路對 CI 和容器最乾淨——不用--background --python,直接import bpy就好,代價是綁死 Python 3.13、而且沒有 GUI 可以打開來檢查。
Agent 常犯的錯是假設 blender 在 PATH 上。在你的 skill 裡寫死已驗證的絕對路徑,這就是 Simon 的 skill 第一段在做的事。
什麼時候該用、什麼時候別用
適合的:
- 程式化、參數化的資產——同一個場景換 20 種顏色 / 尺寸 / 角度,寫一次腳本跑 20 次。
- 技術示意圖與封面圖——需要精確的幾何關係(等角視圖的架構圖、機構爆炸圖、3D 資料視覺化)。
- 需要可版控、可交接的產物——
.py進 git,.blend給設計師接手。 - 需要在 CI 裡重跑的東西——文件裡的示意圖跟著程式版本自動重新渲染。
不適合的:
- 要「好看」而不是要「正確」的圖。Simon 那三張鵜鶘很可愛,但那是三輪迭代 + 一個非常會寫 code 的模型的結果,而且風格明顯是「pastel 玩具感」——這正是程式化建模最容易到達的美學區間。要寫實材質、要人臉、要有攝影感,擴散模型類的圖像生成幾乎一定更快更好。
- 角色動畫、布料 / 流體模擬、雕刻。這些領域的迭代成本高、參數空間大,靠盲寫腳本收斂很慢。
- 趕時間的一次性圖。前面說了,CPU render 一輪就是幾分鐘。
一句話總結 trade-off:這條路買的是「可控與可重現」,不是「省時間」也不是「更漂亮」。
對工程團隊的意義
如果你要把這件事變成團隊能用的能力,我會這樣排:
- 把 Blender 當成另一個 build target,不是設計工具。 場景腳本放進 repo、產物寫進
dist/、能在 CI 跑。這樣定位之後,所有工程慣例(review、版本、重跑)都自動適用。 - 第一天就寫 skill,不要等第三次才寫。 內容照 Simon 那份的骨架:已驗證的絕對路徑與版本、執行指令(含
--python-exit-code 1)、產物放哪、已知的環境坑、視覺 QA 檢查清單。這份檔案的價值在於它記的是你這台機器上的事實。 - 把「回讀渲染圖」寫成硬規則。 沒有這一步,你拿到的就是一堆技術上成功、視覺上災難的 PNG。
- 成本結構要跟團隊講清楚。 這件事貴在 CPU 時間,不在 token。一輪 2–6 分鐘(Simon 回報,CPU Cycles、無 GPU 加速)意味著 agent 會有很長的等待窗口——別讓它在等待期間重複發起渲染,Simon 的 skill 就明確寫了「若執行回傳 session ID,就輪詢那個 session,不要另外再開一個 render」。
- 先挑一個真實的小需求試。 不要從「做一支產品宣傳片」開始。從「把我們架構圖的那顆立方體做成等角視圖 3D 版,換三種配色」這種規模開始,你會在半小時內知道這條路對你的團隊值不值得。
來源
- Simon Willison, 〈Using Blender with coding agents on macOS〉, TIL, 2026-09-05 — https://til.simonwillison.net/llms/blender-coding-agents-macos
- Simon Willison,
simonw/gpt-6-astra-blender-pelican-bicycle(腳本、.blend、渲染圖與 Codex transcript)— https://github.com/simonw/gpt-6-astra-blender-pelican-bicycle - 該專案產出的
blender-localskill — https://github.com/simonw/gpt-6-astra-blender-pelican-bicycle/blob/main/outputs/blender-local/SKILL.md - Blender Foundation, Command Line Arguments, Blender 5.2 LTS Manual — https://docs.blender.org/manual/en/latest/advanced/command_line/arguments.html
- Blender Foundation,
bpyon PyPI(5.2.1, 2026-08-25)— https://pypi.org/project/bpy/ - Siddharth Ahuja,
ahujasid/blender-mcp(MCP 路線對照組)— https://github.com/ahujasid/blender-mcp - Blender issue #82494「An exception in Python script does not change return code of Blender」、#126807「exit status code of 139」
整理:DataAgent · Coding Agent 實戰教學


