預先渲染:生成式視覺與穩定化素材
五條路徑,共用一組通用規則。一個程式繪製的作品變成素材,以 video 形式放置:請先閱讀它。一個SVG 靜態圖變成單張 PNG,以 image 形式放置:請跳至 SVG 路徑。一個Lottie 動畫也變成素材,每幀繪製一個全新的播放器:請跳至 Lottie 路徑。一個3D 場景變成透明素材或靜態 PNG:請跳至 3D 場景路徑。來源影片穩定化會烘焙出一個新片段:請跳至 穩定化路徑。所有操作都在渲染器之外執行,因此每個畫家解碼的都是相同的像素。
Montagent 沒有著色器或腳本檔案 (ADR-0017)。一個在 effects 清單之外的效果,會在你的程式碼中繪製,編碼一次成為素材,然後以普通的 video 形式放置。其格式、結構和畫家維持不變 (ADR-0156 §7, ADR-0233)。
何時使用
優先選擇已命名的路徑。閱讀 montagent://schema/index.json 中的 effects 清單:當某個成員能達成所需效果(模糊、陰影、色調、blend、關鍵色 mask)時,直接使用它。只有當沒有任何成員、繪畫或混合模式能合成該效果時,才使用預先渲染:例如扭曲、馬賽克、鏡頭光暈、粒子、程序化圖案或外部 3D 模型/場景。
當你拿到一個 SVG 格式的向量圖(商標、圖示、插圖),或當靜態圖最適合用 SVG 繪製時,請使用 SVG 路徑。沒有任何元素接受 SVG 檔案 (ADR-0171)。會動畫的 SVG(SMIL 或 CSS)不屬於此路徑:它會被柵格化為單一靜態幀,動畫效果會遺失。請改用已放置圖片的 scale、rotation 和 opacity 屬性進行關鍵幀動畫。
當你拿到一個 3D 資源(.glb、.gltf、.obj、.fbx、.blend、.c4d)或一個 3D 場景時,請使用 3D 場景路徑。沒有任何元素接受 3D 模型或多通道 pass (ADR-0167, ADR-0233)。無頭渲染會在渲染器外部產生透明的 ProRes 4444 / PNG 素材,準備好直接進行 2D 放置。
當你拿到一個 Lottie JSON 檔案(After Effects 導出、LottieFiles 動畫),或當某個動畫最適合從 Lottie 取得時,請使用 Lottie 路徑。沒有任何元素接受 Lottie 檔案 (ADR-0171)。它涉及三項成本:固定解析度: 素材是以你渲染的大小進行柵格化。配方工具鏈: 需要安裝一個 Lottie 播放器來重現作品(絕不能用於渲染專案)。素材大小: 在 1080p 和 25 fps 的條件下,MOV 中的 PNG 串流,從平滑藝術的約 6 MB/秒 到噪點藝術的 141 MB/秒。因此,請以實際顯示的大小進行渲染,不要更大。如果動畫僅包含少數形狀,使用原生 rect、ellipse 和 path 元素進行關鍵幀動畫會更小且保持清晰。
預先渲染的作品是固定不變的素材。其大小、fps 和長度在渲染時就已確定。更改外觀意味著需要重新渲染,因此請先確定需求的尺寸、fps 和時長,並與專案的 fps 保持一致。
通用規則
每條路徑都會讀取這些規則。它們只書寫一次。
- 尺寸。 以實際像素的
width和height,在作品被展示的最大尺寸(在fit、scale以及任何關鍵幀縮放之後)進行柵格化或繪製。切勿從 SVG 的viewBox推導它:viewBox設定的是繪圖的比例,而非像素,並且不同工具對缺少viewBox的檔案處理方式不一。請在配方中直接寫入尺寸。後續的縮放若超過此尺寸,會對柵格進行重採樣,因此請重新執行更大的配方,而不是進行放大。 - 文字。 僅使用已供應(vendored)的字型,或將文字轉換為輪廓。絕不使用系統字型:沒有該字型的機器會顯示其他內容。找不到的字型應視為建置失敗,而非被跳過的文字區塊。例如,
usvg會記錄缺少的字型並跳過該文字,因此build會讀取 SVG 的font-family值,並與你在fonts中列出的字型檔案進行比對,如果柵格化器本身發出關於字型的警告,也會導致建置失敗。 - 配方。 包含原始碼副本、確切命令、工具版本、尺寸,以及解碼後像素的雜湊值,該雜湊值是透過解碼器使用的相同讀取方式取得的。重建報告會顯示匹配成功或第一個差異點,絕不比較檔案位元組。配方會說明其存放位置。
步驟
依序執行每個步驟。當步驟 5 通過時,作品即完成放置。
- 繪製。 使用任何工具編寫程式碼,產生具有固定
width、height和frames數量的 RGBA 幀:在未繪製任何東西的地方保持透明。它將原始 RGBA 寫入標準輸出(stdout),或將 PNG 檔案f00000.png、f00001.png等寫入名為PRERENDER_FRAMES_DIR的資料夾。從PRERENDER_WIDTH、PRERENDER_HEIGHT、PRERENDER_FPS和PRERENDER_FRAMES讀取其尺寸。使用整數運算或固定種子,以確保第二次執行時繪製出相同的位元組。範例作品 是最小的可運作範例。 - 規格。 在程式碼旁邊撰寫一個建置規格:包括
name、out(專案的媒體資料夾)、width、height、fps、frames、render(執行你程式碼的 argv)、files(程式碼需要的所有檔案),以及當程式碼寫入 PNG 時的input為"png"。執行python3 scripts/prerender.py --help查看每個鍵的說明。如果任何函式庫的版本會改變像素(例如 canvas 函式庫、無頭瀏覽器),請加入versions。 - 建置。 執行
python3 scripts/prerender.py build <spec>。它會執行程式碼,編碼一個<name>.mov,解碼它,並在與程式碼繪製結果不同的第一個幀上失敗。讀取其最後一行:N frames, decoded = drawn。 - 放置。 將素材以普通的
video元素加入專案(如下所示),或執行python3 scripts/prerender.py place <project> <placing>,其中<placing>是一個 JSON 檔案{"source": "media/<name>.mov"},加上可選的id、at、x、y、origin、width、height、fit、track、layer。它會輸出包含新元素的專案,因此請將其重新導向到一個新檔案。 - 檢查。 對專案執行
validate並修復所有錯誤。然後執行montagent probe檢查素材,確認其報告有 Alpha 通道(carries: true)。只有在此之後,才對包含該作品的一個 tile 執行frame,並檢查透明部分是否顯示了背景內容。
{
"frame": {"width": 640, "height": 360}, "fps": 25, "background": "#101418", "duration": 480, "output": "out/pulse.mp4",
"tracks": [
{"name": "prerender", "layer": 10, "elements": [
{"id": "pulse", "type": "video", "start": 0, "end": 480, "source": "media/pulse.mov", "source_start": 0, "source_end": 480, "volume": 0, "x": 320, "y": 180, "origin": "center", "width": 320, "height": 240, "fit": "contain"}
]}
]
}
該元素是一個普通的 video:可以對其 opacity、scale 和 position 設定關鍵幀,加入 effects 和 blend,並像任何片段一樣將其放置在某個軌道上。素材沒有聲音,因此 volume 為 0。其 end 減去 start 等於素材的長度;source_end 也是相同的長度。
SVG 路徑
輸入: 一個 SVG 檔案,以及來自通用規則的像素尺寸。
- 供應字型。 使用
montagent fonts vendor供應 SVG 文字所使用的字型,並為每個使用該字型家族的<text>設定font-family屬性。或者在你的繪圖工具中將文字轉換為輪廓,不使用任何字型。 - 規格。 在 SVG 旁邊撰寫一個建置規格,其中
"input": "svg":包含name、out、svg、實際的width和height、render(柵格化器的 argv,其中{width}、{height}和{out}會替換為實際值)、files、fonts和versions。沒有 fps 和幀數。 - 柵格化。 執行
python3 scripts/prerender.py build <spec>會執行柵格化器一次,在渲染器之外。任何能寫入單張 RGBA PNG 的工具都可以:resvg命令列、無頭瀏覽器、Inkscape。跳過系統字型,並像下面的規格範例一樣,將供應好的字型傳遞給它。它會寫入<name>.png及其配方,並在缺少字型時失敗。 - 放置 PNG 作為一個普通的
image元素(如下所示),或執行python3 scripts/prerender.py place <project> <placing>,使用{"source": "media/<name>.png", "duration": <ms>}加上可選的id、at、x、y、origin、width、height、fit、track、layer。 - 檢查。 執行
validate並修復所有錯誤,然後對包含該圖片的一個 tile 執行frame,並檢查透明部分是否顯示了背景內容。
下面是一個範例規格,用於範例 SVG(包含形狀、漸層和以供應字型設定的文字),以其 viewBox 三倍的大小進行柵格化:
{
"name": "mark", "out": "media", "input": "svg", "svg": "sample_art.svg", "width": 480, "height": 270,
"render": ["resvg", "--skip-system-fonts", "--use-font-file", "Inter-Bold.ttf", "-w", "{width}", "-h", "{height}", "sample_art.svg", "{out}"],
"files": ["sample_art.svg"], "fonts": ["Inter-Bold.ttf"],
"versions": {"resvg": ["resvg", "--version"]}
}
PNG 具有內在的像素尺寸,因此它作為普通的 image 進入,且 ADR-0015 的 fit 規則適用於任何 PNG:使用與容器框相同長寬比的 contain,或使用 literal。以其自身尺寸放置,並使用 fit 為 contain,即為 1:1 繪製。若要以比你柵格化尺寸更大的方式顯示它,則會對柵格進行重採樣:請以更大的尺寸重新執行配方。
{
"frame": {"width": 640, "height": 360}, "fps": 25, "background": "#101418", "duration": 2000, "output": "out/mark.mp4",
"tracks": [
{"name": "art", "layer": 10, "elements": [
{"id": "mark", "type": "image", "start": 0, "end": 2000, "source": "media/mark.png", "x": 320, "y": 180, "origin": "center", "width": 480, "height": 270, "fit": "contain"}
]}
]
}
執行 validate。該圖片是一個普通的圖片:可以對其 opacity、scale 和 position 設定關鍵幀,加入 effects,並將其放置在某個軌道上。
Lottie 路徑
輸入: 一個 Lottie JSON 檔案、一個尺寸、一個 fps 和一個幀範圍。Lottie 自身的 w、h 和 fr 是可選擇的輸入,而非規則:尺寸遵循通用規則(作為字面量的最大顯示尺寸),並且你在規格中寫入 fps 和幀數。
- 選擇一個播放器,該播放器能夠寫出 RGBA 幀,並在
versions中記錄其名稱和版本。此技能不會替你挑選播放器:預先渲染只在渲染器之外執行一次,畫家永遠看不到該播放器。範例播放器 是透過pip install thorvg-python==1.1.3安裝的 ThorVG。 - 規格。 在 Lottie 檔案旁邊撰寫一個建置規格,其中
"input": "lottie":包含name、out、lottie、實際的width和height、fps、frames、render、files、fonts和versions。render是播放器的 argv,其中{width}、{height}、{frame}和{out}會替換為實際值:它將單一幀作為原始 RGBA 繪製到{out}。可選的start和step設定每個素材幀對應的 Lottie 幀(幀i對應於start + i * step;step預設為 Lottie 的fr除以fps)。執行python3 scripts/prerender.py --help查看每個鍵的說明。 - 建置。 執行
python3 scripts/prerender.py build <spec>會先讀取 Lottie 檔案並拒絕它,分別列出原因,如果它使用了表達式、播放器未記錄會繪製的圖層效果(請在allow_effects中列出它能繪製的效果),或文字的字型既沒有嵌入的字型輪廓也沒有fonts中的供應檔案。播放器會靜默地忽略所有這些內容,因此繼續進行的建置將會產出一個不同的動畫。然後它會為每個幀執行render,每次都是一個新行程,讀取播放器自身關於其跳過內容的報告(任何包含 skipped、ignored 或 unsupported 的行都應視為建置失敗),編碼一個<name>.mov如編解碼器所述,並在與播放器繪製結果不同的第一個幀上失敗。 - 放置素材作為一個普通的
video元素,或按照步驟中的說明使用place。執行validate和montagent probe檢查 MOV:確認它報告有 Alpha 通道(carries: true)。然後對包含該作品的一個 tile 執行frame,並檢查透明部分是否顯示了背景內容。
為什麼每個幀使用一個全新的播放器。 此工具絕不會將一個播放器向前搜尋(seek)。ThorVG 會忽略低於 0.001 的幀變更,因此搜尋的落點取決於前一次搜尋,而 Skottie 的搜尋會改變其動畫物件。在其它幀之後繪製的幀可能與第一個繪製的相同幀有所不同,且重建結果將無法匹配。透過為每個幀生成一個新行程,每個幀都是在乾淨的狀態下繪製的,從而確保可重複性。
3D 場景路徑
輸入: 一個 3D 模型或場景檔案,以及一個尺寸。
- 選擇一個無頭渲染器,該渲染器能夠以設定的尺寸和幀數輸出 RGBA 幀(透明背景的 ProRes 4444 或 PNG),並在
versions中記錄其名稱和版本。例如 Blender (blender -b -P scene.py)、Unity、Unreal Engine 或自定義路徑追蹤器。 - 規格。 在場景檔案旁邊撰寫一個建置規格,其中
"input": "3d":包含name、out、scene、實際的width和height、fps、frames、render、files、fonts和versions。可選的scene_args用於傳遞場景特定的參數。執行python3 scripts/prerender.py --help查看每個鍵的說明。 - 建置。 執行
python3 scripts/prerender.py build <spec>會執行一次無頭渲染,以指定的尺寸和幀數輸出透明素材。它會對輸出進行編碼、解碼,並驗證像素是否匹配。 - 放置素材作為一個普通的
video元素(若為靜態 PNG 則作為image),或按照步驟中的說明使用place。 - 檢查。 執行
validate,確認素材的carries: true,然後對包含該場景的一個 tile 執行frame。
穩定化路徑
輸入: 一個來源影片檔案。
- 選擇一個穩定化工具,例如
ffmpeg搭配vid.stab濾鏡或melt,並在versions中記錄其版本。 - 規格。 在來源影片旁邊撰寫一個建置規格,其中
"input": "stabilize":包含name、out、source、fps、frames、render、files和versions。可選的stabilize_args用於傳遞特定於穩定化的參數(例如shakiness、accuracy)。執行python3 scripts/prerender.py --help查看每個鍵的說明。 - 建置。 執行
python3 scripts/prerender.py build <spec>會執行穩定化工具,分析來源影片並產出一個新的穩定化素材。 - 放置素材作為一個普通的
video元素,或按照步驟中的說明使用place。注意source_start和source_end可能需要根據穩定化後的裁剪調整。 - 檢查。 執行
validate,然後通過frame視覺確認穩定效果。
配方
配方會與素材並排輸出到 media/ 資料夾,命名為 <name>.recipe.json。它包含確切的命令、工具版本、尺寸、fps、幀數,以及解碼後素材像素的 SHA-256 雜湊值。要驗證重建,請執行 python3 scripts/prerender.py rebuild <recipe>。它會重新渲染素材,將解碼後的像素與記錄的雜湊值進行比較,並報告匹配成功或第一個差異點。
編解碼器
素材以 ProRes 4444 編碼在 QuickTime MOV 容器中(Apple ProRes 4444)。這提供了無損 Alpha 通道支援和廣泛的相容性。如果 ProRes 不可用,則回退到 PNG 序列(PNG in MOV)作為備用。
故障排除
- 建置失敗:像素不匹配。 確保你的繪製程式碼是確定性的:使用固定種子、整數運算,並且沒有系統特定的變化。檢查
versions是否準確反映了用於渲染的函式庫。 - 缺少字型。 使用
montagent fonts vendor供應所有字型。如果你的 SVG 使用了系統字型,請先將其轉換為輪廓,或使用供應的字型。 - Lottie 播放器跳過內容。 檢查播放器的輸出中是否有包含 skipped、ignored 或 unsupported 的行。簡化你的 Lottie 動畫,或使用支援更多功能的播放器。
- 3D 渲染輸出為黑色。 確認你的無頭渲染器設定為輸出帶有 Alpha 通道的 RGBA 像素。檢查場景的照明和攝影機設定。
- 穩定化導致影片裁剪過多。 調整穩定化參數(例如降低
shakiness)或在穩定化之前加入黑邊。