Emoji Party(節拍同步的表情符號世界歌詞影片,Blender Grease Pencil)
使用者提供任何類型的歌曲(音檔)及其歌詞,或提供無歌詞的純樂器曲。你將產出一部完整的 1080p 影片:每個段落有一個可識別的表情符號臉孔,各自處於自己的世界和配色方案中,做一些 relatable 的事情,隨著節拍起舞,歌詞在螢幕上彈出並隨低音震動。已在「Mr Me」(150 BPM,4:12,15 個場景,約 840 個物件,渲染時間約 10 分鐘)上驗證。
0. 創意規則(從使用者學到)
- 主角是傳達情緒的表情符號臉孔,每個場景一個(焦慮、咧嘴笑、纏繃帶、氣喘吁吁、笑哭、噤聲、震驚、書呆子、生氣、火熱、星星眼、拉鍊嘴、金錢眼、光環、派對)。物體(蠟燭、指南針、鑽石)僅作為道具,絕不作為主角。
- 每個主角都有行頭:每個主角都有穿戴配件。說唱風格:帶有吊墜的鏈條、牙套、臉部紋身、耳環和帽子(鴨舌帽、頭巾、水桶帽、毛線帽、皇冠);其他類型請參閱第 0b 節。
- 每個場景都有關聯動作:開車、騎腳踏車、參加考試、用手機拍攝、釣魚、當 DJ、舉重、自拍、撒錢。
- 每個場景一個調色盤,根據歌詞情緒選擇。歌詞風格在場景間保持一致,使影片讀起來像一個整體。
- 一個重複出現的主角(墨鏡表情符號) 負責副歌,並在最後的副歌中帶著整個陣容回歸。
- 繪製原創的表情符號風格角色。不要複製任何廠商的表情符號集。
- 先顯示一個測試場景(或 3 種調色盤選項),獲得同意後再建構所有內容。使用 SendUserFile 發送預覽靜態圖像。
0b. 適應音樂(任何類型)
在選擇任何東西之前先讀取曲目。類型是輸入,而非假設。
- 速度搜尋:搜尋 60-180 BPM,然後根據小鼓或拍掌落在哪裡(第 2 和第 4 拍)來解析是半速還是倍速。Trap 和嘻哈通常讀作 140-150 但感覺是半速;鼓打貝斯(Drum and bass)讀作 170+ 但可以以半速動畫化。存儲
FPB(感覺節拍)和網格節拍。 - 拍號:預設每小節 4 拍;將每小節拍數設為參數(華爾滋為 3,6/8 拍為 6),並在
FR(bar)和小節長度表達式中使用它。 - 速度漂移(現場樂團、較舊錄音):如果 comb 分數較弱或有漂移,則使用追蹤的節拍列表,並為每個節拍鍵入一個
beat_phase屬性,而不是使用固定週期的表達式。 - 幀率:選擇能讓每個感覺節拍得到整數幀的 fps;否則使用 25 並接受分數節拍。
- 按照感覺移動:
- 四拍地板(House、Techno、Disco、Amapiano):每拍均勻彈跳,穩定搖擺。
- 半速(Trap、嘻哈、Drill、Dubstep):第 1 拍重擊,第 3 拍後傾,小的高帽(hi-hat)速度細節。
- Off-beat(雷鬼、Dancehall、Afrobeats、Ska):在 OFFP 上彈跳,臀部以 2 拍週期搖擺。
- 快速(鼓打貝斯、龐克、Hardcore):半速身體,全速手部和道具。
- 慢速(情歌、R&B、靈魂、Lo-Fi):僅搖擺,長週期,幾乎無擠壓,歌詞以慢淡入取代彈出。
- Swing/三連音(爵士、藍調、Shuffle):將 off-beat 延遲到節拍的 2/3。
- 以能量決定切換速率:平靜時 8-16 小節一個場景,副歌時 4 小節,Drop 和高峰時 1-2 小節。
- 根據類型和歌詞決定外觀:選擇屬於該音樂的調色盤、世界、帽子和配件(說唱用鏈條和牙套,舞曲用耳機和遮陽板,鄉村用牛仔帽,民謠用花朵,搖滾用鉚釘)。始終保持表情符號臉孔作為主角,並維持行頭規則:每個主角都有穿戴配件。
- 歌詞風格:重低音曲目用硬彈出和震動;柔和曲目用平滑滑動和淡入;呼喊和 Hook 用較大字體。語言遵循提供的歌詞(永遠不要「修正」方言或洋涇浜語)。
- 純樂器曲:無歌詞圖層;在 Drop 處使用標題、段落名稱或簡短情緒詞,並讓道具講述故事。
- 用一句話與使用者確認讀取結果(BPM、感覺、段落地圖),然後再開始建構。
1. 分析歌曲(工作區)
pip install --break-system-packages -q librosa,然後在 BPM 範圍內對低頻段(<130 Hz)通量進行 comb 搜尋,得到精確的 BPM 和第一拍偏移;列印每小節的 kick(K)和響度(R),以查看前奏、律動、Drop 和靜音部分。不要相信提示中寫的 BPM(Suno 提示說 140;但曲目實際是 150)。- 當 25 fps 能給出每個節拍整數幀時(120、125、150 BPM 可以),就使用它。
- 歌詞時間碼:工作區內無法下載語音模型,且從 shell 上傳到 Descript 存儲會被阻止。調用
Descript file_upload_ui,要求使用者將音檔放入,wait_for_job,然後將export_transcript匯出為 srt。對於清晰的說唱/口語部分,期望逐行時間碼;對於密集或歌唱部分,期望區塊級(或缺失)時間碼;將使用者的實際歌詞與那些時間戳手動匹配,並將剩餘部分均勻地分配到小節中。告訴使用者哪些部分是估算的。 - 撰寫場景表:段落、開始小節、表情符號、世界、動作、調色盤。場景邊界位於小節上(半小節也可以)。在沒有人聲的段落添加純樂器場景(標題卡、Drop)。
2. Blender 設定
- 使用
blender__get_scene_info檢查連線。在清除已儲存檔案前先詢問。及早儲存(要求一個資料夾;Blender 的 Python 可以直接讀取使用者的資料夾,因此將音效條指向原處的音頻,而不是複製它)。 - 扁平 2D:正交相機位於 y=-20,沿 +Y 方向觀看,
ortho_scale為 16(視野為 16 x 9 單位)。所有內容都在 XZ 平面繪製;深度是物體的 Y 值(較大的 Y 值在更後面)。 - 每個場景位於 X = 索引 * 40 處,在自己的集合
S01_...中;相機在位置 X 上使用 LINEAR 鍵(以及在每個場景內的小幅漂移)在它們之間跳躍,並為每個剪輯點設定時間軸標記。 - 色彩:
view_transform='Standard',look 為 None。將可重複使用的程式碼儲存在bpy.data.texts中,並在每次呼叫的頂部使用exec執行。
3. 耗時找到的 Grease Pencil 規則(Blender 5.x)
- 資料是
bpy.data.grease_pencils;layer.frames.new(1).drawing;drawing.add_strokes([n]);設定point.position=(x,0,z)和point.radius;呼叫drawing.tag_positions_changed()。 - 除非每個填滿的筆畫都有非零的
fill_id,否則填滿不會渲染。對填滿使用stroke.fill_id = unique int,對線條使用 0,並在僅填滿的筆畫上設定stroke.hide_stroke = True。對一個文字字形的所有閉合迴圈使用相同的 fill_id,以便字母內孔能被切除。 - 材質:
bpy.data.materials.create_gpencil_data(m);show_fill/show_stroke;透過fill_style='GRADIENT'實現徑向漸層。材質顏色是線性的:使用(v/255)**2.2轉換十六進制,否則所有顏色看起來都會很淡。 - 在每個圖層上設定
layer.use_lights = False。 - 字型/曲線文字物件在渲染時會被 Grease Pencil 遮擋。 將文字轉換為 GP:建立一個臨時的 FONT 曲線,
evaluated_get(dg).to_curve(dg),使用mathutils.geometry.interpolate_bezier取樣貝茲曲線,將閉合迴圈繪製為 GP 筆畫(先畫輪廓筆畫,再畫填滿)。在單獨的暫存場景中進行臨時工作,這樣主場景的 depsgraph 就不會因每個文字而重新求值(此方式處理 486 個文字僅需 3 秒)。 - 半透明填滿疊加在半透明填滿上看起來很混濁;對於光線和光暈,偏愛使用不透明的深色。
- 驅動程式:自動執行 Python 通常已關閉,因此每個驅動程式必須是一個簡單的表達式(
sin abs exp fmod min max pi frame);斷言driver.is_simple_expression。
4. 節拍表達式(F0 = 第一拍幀數,FPB = 每節拍幀數)
PULSE = exp(-fmod(frame-F0+BIG, FPB)/(FPB*0.25)) # 每拍為 1,衰減
OFFP = 同上,偏移半拍 # 弱拍
HALF = exp(-fmod(frame-F0+BIG, 2*FPB)/(FPB*0.45)) # 每 2 拍
OFFB = HALF 偏移一拍
SWAY(per,ph) = sin(pi*(frame-F0)/(FPB*per)+ph)
FR(bar) = F0 + round(4*FPB*bar)
dance(obj):位置 Z += bouncePULSE,縮放 X (1+squashPULSE),縮放 Z (1-squashPULSE),旋轉 Y += swaySWAY。在相鄰物件之間交替使用 PULSE 和 OFFP。雙手在 HALF/OFFB 上聳肩。相機 ortho_scale = 16*(1 - zoom*PULSE),帶有一個有鍵入的 zoom 自訂屬性(在 Drop 和副歌中更大)。
5. 一次性建立的輔助函式庫
- 形狀:
ell(橢圓)、rect(矩形)、rrect(圓角矩形)、star(星形)、drop(水滴);F(填滿)、S(線條)、P(填滿 + 墨線輪廓)。 emo(C,name,x,z,r,mood):陰影、黃色漸層圓盤、光澤,然後根據情緒繪製特徵。儲存o["r"]=r以便配件縮放。- 行頭:
chain(o,pendant,ice)(鏈條)、grills(o)(牙套)、tattoo(o,kind,side)(紋身,類型包括淚滴、十字、星星、線條、文字)、earring(o,side)(耳環)、hat(o,kind,col,col2,tilt)(帽子,作為子物件)、headphones(o)(耳機)、hand(...)(手,可帶戒指和手錶)。 - 世界:
sky(C,X,top,mid,bot)(天空,16 色條帶)、ground(地面)、city(城市天際線,帶有發光窗戶)、wheel(輪子,帶有旋轉驅動器)、phone(手機)。 preview(shots)(預覽):以 33% 渲染靜態圖到 /tmp,並使用montage(paths)用 numpy 將它們拼貼成一個圖像;使用blender__look(image=path)查看。在渲染前以這種方式檢查每個場景。
6. 歌詞圖層
- 資料:列表
(kind, t0, t1, text),kind 為L(歌詞行)、A(即興詞)、H(Hook 詞)、B(大聲呼喊)。將其作為 JSON 儲存在文字區塊中。 L:將文字分割成單詞,在大小為 0.78、間距為 0.44 的情況下,換行至 14.4 單位寬,置於畫面頂部。每個單詞都是自己的 GP 物件,在start + i*step處出現(step 從行持續時間計算,2 到 8 幀),並在下一行開始或場景切換時隱藏。- 每個單詞的驅動程式:
scale = vis * pop * (1+0.10*PULSE),其中vis是 2 幀的淡入/淡出斜坡,pop是 6 幀的過衝;location X/Z += shake*sin(frame*k+ph)*PULSE用於低音震動。 A:粉紅色、傾斜、交替左右。H:黃色、底部、從上方落下。B:金色、大小 1.5、頂部。- 將每個場景的歌詞物件放入
LYR_Sxx集合中,以便渲染區塊可以隱藏其餘部分。
7. 渲染(快速路徑)
- 全場景渲染約 1.3 秒/幀,因為每個 GP 物件都會被求值。改為並行渲染每個場景的一個區塊:為每個場景啟動一個背景 Blender,設定對除
Sxx_、LYR_Sxx和CAMERA以外的所有集合hide_render,移除音效條,並寫入無音訊的 H264。每次從分離的執行器進程(start_new_session=True)運行 5 個,並記錄到render_log.txt。 - 然後在一個工廠空場景中組合,在每個場景的起始幀處放置影片條(movie strips),再加上音效條,輸出 H264 + AAC。將該場景的 view transform 設定為 Standard,否則最終影片會變暗且去飽和(工廠預設為 AgX)。
- 在最終檔案驗證完成前,不要刪除區塊。
- 驗證:將 mp4 載入為 movieclip(檢查幀數、fps、尺寸)和音效(檢查取樣率、通道數);透過具有 Standard view transform 的臨時序列器場景提取約 16 幀,製成接觸表(contact sheet)並查看。背景日誌中的
bgl插件回溯訊息是無害的。 - 不要在緊湊迴圈中輪詢;每次檢查之間休眠約 5 分鐘,並告訴使用者預期時間。
8. 交付
- 告知 mp4 和 .blend 檔案的位置(以純文字加上一個 computer:// 連結的形式),並發送接觸表。
- 說明哪些內容未被檢查(你只看到了靜態圖,而非播放),以及哪些歌詞段落是估算的。
- 提供按場景或按歌詞行的修正選項;時間軸標記代表剪輯點,歌詞 JSON 包含時間碼。