Blender 動畫 — 基於 Python 的 3D 工作流程
透過 bpy 驅動 Blender,在背景模式下執行可重複運行的腳本。將 .blend 檔案視為腳本的建構產物:腳本才是真正的原始碼,檔案則是最終交付物。
請參閱 references/BLENDER-PLAYBOOK.md 以了解架構與判斷準則,並參閱 references/BLENDER-RECIPES.md 以取得可直接複製的程式碼模式。務必針對已安裝的 Blender 版本核對 API 文件;不同版本間的 Python API 可能有所變更。
1. 首先驗證環境
blender --version
blender --background --factory-startup --python-expr \
"import bpy, sys; print('BLENDER', bpy.app.version_string); print('PY', sys.version.split()[0]); print('ENGINES', [e.bl_idname for e in bpy.types.RenderEngine.__subclasses__()][:5])"
規則:
bpy屬於 Blender 內建的 Python。絕對不要pip install bpy,也不要使用系統 Python 執行場景腳本。- 加上
--python-exit-code 1參數,讓 Python 例外會導致 shell 命令失敗,而不是悄悄的成功。 - 使用
--factory-startup進行乾淨建構;但絕對不要用它清掉使用者正在編輯的專案。 - 每次渲染開始時,都要記錄 Blender 版本、引擎、影格範圍、解析度、FPS 與輸出路徑。
2. 標準呼叫方式
# 從頭建立場景並儲存 .blend 檔案
blender --background --factory-startup --python-exit-code 1 --python blender/scripts/build_scene.py
# 修改既有專案
blender --background project.blend --python-exit-code 1 --python blender/scripts/update_scene.py
# 渲染已儲存的動畫
blender --background project.blend --render-anim
# 渲染單一影格
blender --background project.blend --render-frame 120
# 安全地渲染一個範圍(影像序列)
blender --background project.blend --python-exit-code 1 --python blender/scripts/render_frames.py
長時間工作請將輸出重新導向到 logs/ 目錄,並且優先使用影像序列,以便在需要時可以繼續渲染。
3. 腳本架構
對於小型場景,可以只使用一個檔案。當場景超過 300 行或包含多個鏡頭時,請拆分為以下結構:
blender/
config.py # fps、影格範圍、解析度、調色盤、路徑、隨機種子
build.py # 進入點:重置 → 設定 → 建構鏡頭 → 儲存
scene_setup.py # 世界、單位、集合、渲染設定
geometry.py # 基本幾何體、曲線、參數化網格
materials.py # 節點建構器、可重複使用的材質工廠
animation.py # 關鍵幀、驅動器、程序動畫
camera.py # 攝影機支架、軌道/推軌、景深、畫面構圖檢查
lighting.py # 主光/補光/邊光、HDRI、自發光點綴
simulation.py # 粒子、剛體、布料 — 快取設定
render.py # 引擎、取樣、輸出、聯繫表、編碼
shots/ # 每個鏡頭一個模組:shot_01.py、shot_02.py
絕不妥協的事項:
- 冪等性。 重複執行只會更新您命名的集合/物件;絕不會複製幾何體或清除不相關的使用者內容。
- 命名。
Main_Logo、Cam_Orbit、Light_Key、Emitter_Particles。絕對不要使用Cube.003。 - 可配置。 所有可調整的數值都放在
config.py或一個 dataclass 中,這樣修訂只需更改一行。 - 斷言。 如果缺少資源、攝影機、字型或輸出目錄,要大聲報錯。
- 範圍限制。 清理時只刪除您擁有命名權的集合,例如使用
MS_前綴。
4. 場景建構
- 優先使用資料 API(
bpy.data.objects.new、bpy.data.meshes.new、collection.objects.link),而不是依賴上下文、選取狀態、模式或區域的bpy.ops。 - 如果確實需要使用運算子,請為該版本提供適當的上下文覆蓋,並說明原因。
- 透過節點和小型工廠函數建立材質;不要為每個物件複製貼上 20 個節點的樹。
- 使用真實世界比例,並設定場景單位系統;比例錯誤會破壞景深、物理和照明。
- 明確設定世界節點樹(顏色、強度、HDRI),以便在不同機器上重現渲染結果。
- 嵌入或路徑相對化資源。
//assets/...路徑加上資料夾,優於絕對路徑指向某人的下載目錄。
5. 動畫
有意識地選擇機制:
| 需求 | 使用方式 |
|---|---|
| 手工編寫的位置/旋轉/縮放/材質變化 | 關鍵幀,搭配明確的插值模式 |
| 某屬性跟隨另一屬性或表達式 | 驅動器(簡單、有說明的表達式) |
| 重複/參數化動畫(軌道、波浪、網格、螺旋) | 依影格計算數學,無狀態執行 |
| 數千個實例、圖案、散佈 | Geometry Nodes(幾何節點) |
| 物理湧現的運動 | 模擬(快取,驗證全範圍) |
| 沿空間曲線的攝影機路徑 | 曲線 + 跟隨路徑約束,或關鍵幀化支架 |
關鍵幀的衛生習慣:
obj.location = (0, 0, 0)
obj.keyframe_insert("location", frame=1)
obj.location = (4, 0, 0)
obj.keyframe_insert("location", frame=48)
for fc in obj.animation_data.action.fcurves:
for kp in fc.keyframe_points:
kp.interpolation = 'BEZIER'
kp.easing = 'EASE_IN_OUT'
kp.handle_left_type = kp.handle_right_type = 'AUTO_CLAMPED'
- 有目的地設定插值模式。預設的貝茲適合有機動作;使用
LINEAR表示恆定速度和機械運動;使用CONSTANT產生階梯或像素風效果。 - 避免在循環動畫中留下非本意的緩入/緩出,這會在循環點產生卡頓。
- 對於循環:讓影格 1 和影格 N+1 完全相同,然後渲染
[1, N]。 - 所有程序動畫必須是影格的純函數:
f(frame)。不要使用累積狀態或未設定種子的random。
6. 幾何節點與實例化
當需要規模、變化或非破壞性控制時,使用 Geometry Nodes(幾何節點):
- 散佈/實例(樹木、碎片、星星、人群方塊)。
- 參數化陣列、網格、徑向圖案、伊斯蘭幾何鑲嵌。
- 動畫位移、場域、以及每個實例的旋轉/縮放。
- 將包含 10,000 個物件的沉重 Python 迴圈轉換為一個節點樹。
使用 nodes.new(...) 和 links.new(...) 按名稱建立節點,不要依賴脆弱的索引。將使用者會要求調整的旋鈕(數量、半徑、種子、速度)暴露為修改器的輸入參數,這樣修訂無需更改程式碼。
7. 材質、燈光、攝影機
- 材質: 以 Principled BSDF 為基礎;明確設定粗糙度/金屬度;使用自發光做點綴(保持克制 — 泛光無法拯救平淡的畫面)。只有在必要時才使用真正的透明材質,並在最終引擎中驗證。
- 燈光: 主光 → 補光 → 邊光 → 環境光。形狀和深度優先於裝飾。檢查曝光和高光裁切,而不只是視埠效果。
- 攝影機: 根據主體選擇焦距和構圖。軌道、推軌、升降、或鎖定,每個動作都必須有理由。檢查極端影格(不僅是第 1 影格)的構圖。優先使用平滑的貝茲手柄;在停止點加上微小的緩衝,而不是硬停。
- 景深: 對焦在故事重點上;不要模糊小字。
8. 引擎與渲染設定
| 引擎 | 用途 | 成本 |
|---|---|---|
| EEVEE | 動態圖形、風格化工作、快速迭代、預覽 | 低 |
| Cycles | 擬真光照、反射、全域照明、玻璃、最終成品 | 高 |
| Workbench | 分鏡、剪影、動畫腳本 | 非常低 |
不確定時兩種引擎都測試;引擎速度取決於場景,而非行銷說法。GPU 表現取決於建構、驅動程式和作業系統 — 務必保留 CPU 備用方案。
明確設定並記錄:
scene.render.engine = 'BLENDER_EEVEE_NEXT' # 4.2+;舊版可能使用 'BLENDER_EEVEE'
scene.render.resolution_x, scene.render.resolution_y = 1920, 1080
scene.render.resolution_percentage = 100
scene.render.fps, scene.render.fps_base = 30, 1.0
scene.frame_start, scene.frame_end = 1, 300
scene.render.image_settings.file_format = 'PNG'
scene.render.image_settings.color_mode = 'RGBA'
scene.render.filepath = "//renders/shot_01/frame_"
- 預覽:25–50% 解析度、低取樣數、EEVEE 或 Workbench。
- 最終成品:全解析度、根據風格選擇引擎、必要時使用降噪、正確的視角轉換。
- 色彩:決定視角轉換(AgX/Filmic/Standard)一次,套用到所有通道,並在下游的 Remotion/FFmpeg 中保持一致。不匹配的視角轉換是「合成結果看起來褪色」最常見的原因。
- 長時間渲染 → PNG(需要 HDR 時用 EXR)序列,然後編碼。直接輸出影片只用於快速檢閱。
9. 預覽階梯
- 一張代表性影格的靜止圖。
- 關鍵影格:開頭、揭示、高潮、每個轉場、結尾。
- 低取樣、低解析度的片段,包含最難的動作。
- 縮小比例的完整預覽,使用真實 FPS。
- 只有當第 1–4 步看起來正確時,才進行最終渲染。
使用聯繫表加上特定影格進行檢查:
ffmpeg -i preview.mp4 -vf "fps=2,scale=320:-1,tile=4x4" -frames:v 1 previews/contact.jpg
檢查是否有閃爍、Z 軸衝突、彈出、交疊、紋理浮動、攝影機裁切、曝光變化,以及難以閱讀的文字。
10. 文字、多語言與 Logo 工作
- 只有在確認文案和字型授權後,才將文字轉換為網格;在原始碼中保留可編輯的文字物件。
- 在製作動畫前驗證字元涵蓋範圍。對於波斯文/阿拉伯文,請檢查渲染影格中的連字、形狀變換、從右到左順序、變音符號和混合腳本標點符號 — 即使字串正確,如果文字路徑沒有正確造型,渲染結果仍可能錯誤。
- 對於品牌/Logo 工作,盡可能取得向量來源;如果是點陣圖,請有意識地進行描摹,並在 4K 解析度下檢查邊緣。
- 對文字進行倒角/加粗,使其能承受光線;避免純黑對黑或純白對白的邊緣。
11. 效能與可靠性
- 使用實例,不要複製。降低細分級別,而不是降低取樣數。
- 限制透明圖層和體積效果;它們通常是渲染時間的殺手。
- 快取模擬,並確認快取存在於專案內或有相關文件說明。
- 對於易碎的工作,以影格批次的方式渲染;在編碼前確認影格數量並捕捉遺失的影格。
- 監控 RAM/VRAM/磁碟空間。4K EXR 序列很大;在長時間渲染前檢查可用空間。
- 在用較新版本的 Blender 開啟/儲存
.blend檔案前先備份 — 較新的檔案可能無法在舊版中開啟。
12. 最小可工作範例
# build.py — 使用以下命令執行:
# blender --background --factory-startup --python-exit-code 1 --python build.py
import bpy, bmesh, math, os
scene = bpy.context.scene
scene.frame_start, scene.frame_end = 1, 120
scene.render.fps = 30
scene.render.resolution_x, scene.render.resolution_y = 1920, 1080
scene.render.engine = 'BLENDER_EEVEE_NEXT'
scene.render.filepath = "//renders/frame_"
# 清理所屬集合
col = bpy.data.collections.get("MS_Main") or bpy.data.collections.new("MS_Main")
if col.name not in scene.collection.children:
scene.collection.children.link(col)
def add_sphere(name, loc, radius, mat):
"""資料 API 球體:不使用運算子,沒有上下文依賴。"""
mesh = bpy.data.meshes.new(name)
bm = bmesh.new()
bmesh.ops.create_uvsphere(bm, u_segments=32, v_segments=16, radius=radius)
bm.to_mesh(mesh)
bm.free()
obj = bpy.data.objects.new(name, mesh)
obj.location = loc
col.objects.link(obj)
obj.data.materials.append(mat)
return obj
mat = bpy.data.materials.new("MS_Emission")
mat.use_nodes = True
bsdf = mat.node_tree.nodes["Principled BSDF"]
bsdf.inputs["Base Color"].default_value = (0.05, 0.6, 0.55, 1)
bsdf.inputs["Emission Color"].default_value = (0.1, 0.9, 0.8, 1)
bsdf.inputs["Emission Strength"].default_value = 3.0
bsdf.inputs["Roughness"].default_value = 0.3
core = add_sphere("MS_Core", (0, 0, 1), 0.8, mat)
core.keyframe_insert("scale", frame=1)
core.scale = (1.15, 1.15, 1.15)
core.keyframe_insert("scale", frame=40)
core.scale = (1.0, 1.0, 1.0)
core.keyframe_insert("scale", frame=90)
# 攝影機
cam_data = bpy.data.cameras.new("MS_Cam")
cam = bpy.data.objects.new("MS_Cam", cam_data)
col.objects.link(cam)
scene.camera = cam
cam.location = (6, -6, 3)
cam.rotation_euler = (math.radians(75), 0, math.radians(45))
# 儲存
os.makedirs(bpy.path.abspath("//renders"), exist_ok=True)
bpy.ops.wm.save_as_mainfile(filepath=bpy.path.abspath("//scene.blend"))
print("BUILD OK", len(col.objects), "objects")
更多內容請參閱 references/BLENDER-RECIPES.md:軌道支架、緩入/緩出、Geometry Nodes 散佈、粒子、文字、Alpha 通道、渲染農場腳本、以及編碼命令。
13. Blender MCP(可選的便利工具)
背景模式腳本是生產路徑:可重複、可比對、可除錯、CI 友善。MCP 僅適用於在已開啟的會話中進行互動式場景檢查和即時調整。它是第三方整合,而非 Blender 的內建組件。
如果使用者需要:請審查儲存庫和授權,檢查與已安裝 Blender 的相容性,了解它授予在 Blender 內執行任意 Python 的能力,將其綁定到 loopback,且絕不要暴露到不安全的網路。目前套件名稱為 mcp-for-blender;請依照儲存庫當前的設定說明進行操作,而不是使用舊的 blender-mcp 片段。不要將其設為任何交付專案的依賴項。
14. 交付物
一個 Blender 工作完成的標誌是擁有以下項目:
output/final.mp4(或要求的格式),已使用ffprobe驗證。blender/scripts/*.py— 建構原始碼。scene.blend— 可編輯的專案,資源已嵌入或使用相對路徑。- 保留
renders/影像序列(或已記錄的主檔案),如果仍有用途。 README.md— 精確的 Blender 版本、安裝方式、建構、預覽、最終渲染和修訂命令。- 一份簡短的報告:使用的工具、解析度、FPS、時長、影格數、以及視覺上驗證過的項目。
當使用者要求一個他們可能想要修改的動畫時,絕不要只交付 MP4 檔案。