Emoji Party(节拍同步的 emoji 世界歌词视频,Blender Grease Pencil)
用户提供任意曲风的歌曲(音频文件)及其歌词,或为纯乐器曲无歌词。你输出一个完整的 1080p 视频:每个段落一个可识别的 emoji 面部,各有独立的世界和配色方案,做着常见活动,随着节拍起舞,歌词在屏幕上弹出并随低音震动。已在 "Mr Me"(150 BPM,4:12,15 个场景,约 840 个物体,渲染约 10 分钟)上验证。
0. 创意规则(从用户处学习)
- 主角是承载情绪的 emoji 面部,每个场景不同(焦虑、咧嘴笑、缠绷带、生气、笑哭、嘘、惊呆、书呆子、愤怒、热、星星眼、拉链嘴、金钱嘴、光环、派对)。物体(蜡烛、指南针、钻石)仅为道具,决不是主角。
- 每个主角都有装扮:说唱类包括带有吊坠的链子、牙钻、面部纹身、耳环和帽子(棒球帽、头巾、渔夫帽、无边帽、王冠);其他曲风见 0b 节。
- 每个场景的可关联动作:开车、骑自行车、考试、用手机拍摄、钓鱼、打碟、举重、自拍、撒钱。
- 每个场景一个配色方案,选自歌词的情绪。歌词风格在所有场景中保持一致,使视频读起来像是一个整体。
- 一个重复出现的主角(墨镜 emoji)拥有副歌部分,并在最后一段副歌中与全体演员一起回归。
- 绘制原创的 emoji 风格角色。不要复制任何供应商的 emoji 集。
- 先展示一个测试场景(或 3 个配色选项),得到肯定后再构建所有内容。使用 SendUserFile 发送预览静止帧。
0b. 适应音乐(任意曲风)
在选择任何内容之前先读取曲目。曲风是输入参数,而非假设。
- 速度搜索:搜索 60-180 BPM,然后通过军鼓或拍手声落在的拍子(第 2 和第 4 拍)分辨半速/双倍时间。Trap 和嘻哈常读作 140-150 但感觉是半速;鼓打贝斯读作 170+ 但可以按半速动画。存储
FPB(感觉拍)和网格拍。 - 拍号:默认为每小节 4 拍;使拍每小节的 beats-per-bar 成为一个参数(华尔兹为 3,6/8 为 6),并在
FR(bar)和小节长度表达式中使用它。 - 速度漂移(现场乐队、旧录音):如果 comb 分数弱或漂移,则使用跟踪的节拍列表,并为每个节拍设置
beat_phase属性,而不是使用固定周期表达式。 - 帧率:选择能使每个感觉拍为整帧的 fps;否则用 25 并接受分数拍。
- 按感觉移动:
- 四拍地板(house、techno、disco、amapiano):每拍均匀弹跳,稳定摇摆。
- 半速(trap、嘻哈、drill、dubstep):第 1 拍大击,第 3 拍后倾,小的高帽节奏细节。
- 弱拍(reggae、dancehall、afrobeats、ska):在 OFFP 上弹跳,臀部按两拍周期摆动。
- 快速(鼓打贝斯、朋克、硬核):半速身体,全速手和道具。
- 慢速(民谣、R&B、灵魂乐、lo-fi):仅摇摆,长周期,少压扁,歌词缓慢淡出而非弹出。
- 摇摆/三连音(爵士、布鲁斯、shuffle):将弱拍延迟到节拍的三分之二。
- 根据能量决定剪切频率:平静时每 8-16 小节一个场景,副歌时 4 小节,在 drops 和 peaks 处 1-2 小节。
- 通过曲风和歌词确定外观:选择属于该音乐风格的调色板、世界、帽子和配饰(说唱配链子和牙钻,舞曲配耳机和遮阳板,乡村配牛仔帽,民谣配花,摇滚配铆钉)。始终让 emoji 面部作为主角,并保持装扮规则:每个主角都有装扮。
- 歌词风格:重低音曲目使用硬弹出和震动;轻柔曲目使用平滑滑动和淡出;咏唱和 hook 使用更大字体。语言遵循给定歌词(绝不“纠正”方言或混合语)。
- 纯乐器:无歌词层;在 drops 处使用标题、段落名称或简短的情绪词,让道具承载故事。
- 用一行文字确认对曲目的理解(BPM、感觉、段落映射)后再开始构建。
1. 分析歌曲(工作空间)
pip install --break-system-packages -q librosa,然后在低波段(<130 Hz)通量上对 BPM 范围进行 comb 搜索,得到精确 BPM 和第一拍偏移量;打印每小节的踢鼓 (K) 和响度 (R) 以查看前奏、律动、drops 和空白段。不要信任提示中写的 BPM(Suno 提示说 140;实际曲目是 150)。- 在 fps 能给出每拍整帧时使用 25 fps(120、125、150 BPM 可以)。
- 歌词时间轴:语音模型无法在工作空间下载,且上传到 Descript 存储被 shell 阻止。调用
Descript file_upload_ui,要求用户将音频放入,wait_for_job,然后export_transcript为 srt 格式。对于清晰的说唱/口语部分期望行级时间轴,对于密集或歌唱部分期望块级(或缺失)时间轴;手动将用户的真实歌词与这些时间戳匹配,其余部分按小节均匀估计。告知用户哪些部分是估计的。 - 编写场景表:段落、起始小节、emoji、世界、动作、调色板。场景边界位于小节上(半小节也可以)。在声乐静音处添加乐器场景(标题卡、drop)。
2. Blender 设置
- 使用
blender__get_scene_info检查连接。在清除已保存文件前询问。提前保存(要求一个文件夹;Blender 的 Python 可以直接读取用户的文件夹,因此将音轨指向原位置的音频而非复制它)。 - 平面 2D:正交相机在 y=-20 处沿 +Y 方向观看,
ortho_scale16(视野为 16 x 9 单位)。所有内容在 XZ 平面上绘制;深度是物体的 Y(Y 越大越靠后)。 - 每个场景位于 X = index * 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)) # 每两拍
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 自定义属性(在 drops 和副歌中更大)。
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即兴添加、Hhook 单词、B大声喊叫。将其存储为文本块中的 JSON。 L:拆分为单词,在 0.78 大小下换行为 14.4 单位宽,间隙 0.44,位于帧顶部。每个单词是其自己的 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。 - 然后在工厂空的场景中组装,每个场景的起始帧处放置影片条,加上音轨,输出 H264 + AAC。将该场景的 view transform 设置为 Standard,否则最终视频会变暗且褪色(工厂默认是 AgX)。
- 在最终文件被验证前不要删除块。
- 验证:将 mp4 作为 movieclip 加载(帧数、fps、尺寸)和作为声音加载(采样率、通道数);通过临时序列编辑器场景(Standard view transform)提取约 16 帧,生成联系表并查看。后台日志中的
bgl附加组件回溯无害。 - 不要在紧密循环中轮询;在检查之间睡眠约 5 分钟,并告知用户预期时间。
8. 交付
- 告知 mp4 和 .blend 文件的位置(纯文字加上 computer:// 链接),并发送联系表。
- 说明哪些内容未被检查(你看到的是静止帧,而非播放),以及哪些歌词部分是估计的。
- 提供按场景或按歌词行的修复;时间轴标记是剪切点,歌词 JSON 包含时间轴。