平涂动画
单张绘图持续 3-4 帧,动画表现通过切换绘图和口型来实现。对于简单的电视卡通设计,这是能保持图像模型最一致性的路线。它既不需要 3D,也不需要视频模型。
脚本位于本技能的 scripts/ 文件夹中,路径相对于此 SKILL.md。下文用 $S 表示该文件夹。除 new_project.py 外,请在你的电影项目文件夹中运行它们。如果遇到环境问题,请使用 dula-start。
用对方的语言与他们交谈。
工作流程
python $S/new_project.py my_film && cd my_film
1. 故事与镜头
编写 story.md,然后编写 config/film.json(参见 film.json 参考)。第一个短片控制在 20-30 秒内,一句台词大约需要 2-3 秒,所以 15 秒可以容纳 3-5 句台词。仅使用原创角色。
对每一句台词,都要思考谁说、对谁说、以及镜头展示谁。笑话不应依赖于观众听不懂的词语。因果关系也需要绘图来表现(跑进来 → 抓住 → 物体飞走)。不要用切镜来跳过。
2. 角色设计(最重要的一步)
将每个角色放入 config/anchors.tsv 中(名称<TAB>外貌描述),然后运行:
python $S/paint.py anchors config/anchors.tsv
亲自打开并查看每张图片。 一些查看器会将透明区域显示为黑色背景上的彩色辉光,这看起来像失败的剪影。如有疑问,请检查步骤 3 中的 build/check_alpha.png。然后向对方展示设计并征得批准,然后再继续。之后的每一张绘图都基于这些设计,因此这里的错误代价最高。用语言描述来修正比例,例如“头部占身高的三分之一,圆脸,黑色小珠眼,红色工装裤”。
3. 背景与绘图
填写 config/plates.tsv(名称<TAB>描述)和 config/cels.tsv(绘图名称<TAB>角色<TAB>姿势)。绘图名称以角色名开头,如 hero_run_a。
python $S/paint.py plates config/plates.tsv
python $S/paint.py cels config/cels.tsv
python $S/prep_cels.py --bases-only # 在绘制口型前检查 build/check_alpha.png 中的剪影
每张图片需要 1-3 分钟生成,paint.py 会报告进度。如果你的工具会终止长时间运行的命令,请在后台运行它。重新运行会跳过已完成的图片。要重做某张图片,请使用 --only <名称> --force。
要保持绘图和场景的连续性,可以添加一列命名要参考的图片:
hero_run_a hero 向右跑,左脚在前。
hero_run_b hero 向右跑,右脚在前。 hero_run_a
meadow 灰雨云下的草地。
meadow_sun 雨停了,阳光穿透云层。 meadow
规则:
- 每张图片只绘制一个角色。角色设计始终是第一参考。切勿使用被拒绝的图片作为参考。
- 首先决定角色的朝向。 逐张生成的图片各自选取方向,因此对话中的两个人很容易变成背对背。提前指定朝向,并使用
flip来修正错误。 - 动作循环中的每张绘图应参考前一张(上面的附加列),这样方向、比例和形状才能保持稳定。没有这个,循环就会产生跳跃感。
- 要改变一天中的时间,重新绘制背景,并参考原始背景图。乘色无法隐藏蓝天。
- 检查每个镜头中角色的比例。像“脖子向上伸长”这样的姿势描述可能会导致身体变形。
4. 口型与眨眼
每张说话的绘图都需要在同一图像上进行局部编辑。在 config/variants.tsv 中:
hero_stand_m1 hero_stand 仅将嘴巴改为半开的小椭圆。
hero_stand_m2 hero_stand 仅将嘴巴改为大张开。
hero_stand_blink hero_stand 将双眼闭上为简单的曲线。不改动其他任何部分。
命名:<基础>_m1 为半开,<基础>_m2 为大张。如果只有 _m1,则嘴巴有两种状态:张开和闭合,这也有效。基础绘图本身必须嘴巴闭合。如果在绘制时嘴巴是张开的,则创建一个闭合变体,并在 film.json 中使用 talk 设置所有三种状态。
每个说话角色的每张绘图都需要自己的口型变体,包括行走循环中的每张绘图。
python $S/paint.py variants config/variants.tsv
python $S/prep_cels.py
prep_cels.py 将绘图压缩为真正的纯色,并将每个变体锁定到其基础图像。然后打开 build/check_alpha.png 并在品红色背景上检查剪影。重新绘制任何残留背景、缺失部分或眼睛被擦除的图像。如果它警告有较大的区域变化,则说明模型修改了身体。在 variants.tsv 的第 4 列添加一个窗口 x,y,w,h。
颜色在漂移? 你可以添加 config/palette.json(例如 {"skin": [250, 220, 190]}),使用从角色设计中采样的颜色。只有相近的颜色会吸附到它,并且 prep_cels.py 会在你修改后再次应用它。
5. 声音
选择一种方式:
- 使用
dula-voice生成语音,需使用对方自己的密钥。 - 使用现有音频:将其放在
audio/voice/<台词ID>.wav,或在台词上设置file。mp3 和 wav 都有效。 - 制作无声草稿:为台词提供
seconds值。
口型是根据此音频计算的,因此在制作测试片前要确定好语音。
可选:ambience(环境音)、bgm(背景音乐)、sfx(音效)和 songs(歌曲)。仅使用对方拥有使用权的素材。本项目不生成音乐。如果没有许可的音乐,就省去配乐,让环境音和音效来承载影片。
6. 测试
python $S/build_film.py
python $S/render.py --stills 1,3,5,8,12
python $S/render.py --range 0,20 -o output/pilot.mp4
当可见角色说话但嘴巴无法移动时,build_film.py 会报错停止,这是最容易遗漏的错误。在展示测试片之前,查看每一张静帧。 不要等到整部影片完成才展示给任何人。
让角色站到地面上:猜测 ground 值,渲染一张静帧,然后调整。这比计算快。
不要让镜头静止不动。除非某个节拍故意静止,否则给每个镜头安排一个动态元素:平移背景(pan)、使用 bob 或 shake、切换绘图、或者添加覆盖层(如下雨)。在最后一个镜头用 fade_out 结束影片。
7. 全片与最终检查
python $S/render.py
python $S/check_mouths.py
在交付前确认以下每一项,如果无法做到,请明确说明:
- 你查看了每个镜头的一个真实帧
-
check_mouths.py未报告冻结的口型 - 每个角色在跨镜头时看起来仍然是同一个人(面部和比例比颜色更重要)
- 对话中的人物彼此面向对方
- 在屏幕上移动的单张绘图有
bob或更多绘图,否则会看起来像是在滑动 - 你听过了影片。如果你无法听,请说明音频未经耳朵检查
完整示例
本仓库中的 examples/rainy-slide 包含了一个 15 秒完成影片的提示词和镜头列表,docs/tutorial.md 对其进行了说明。从本文件路径可找到它们:../../examples/rainy-slide 和 ../../docs/tutorial.md。当有人要求看示例时,将它们作为模型使用。
节奏
经验法则:每个镜头平均持续 3-5 秒,每个绘图持续 3-4 帧(约每秒 7 个绘图),频繁使用特写和夸张表情。hold 是每个绘图持续的帧数。
常见问题
| 症状 | 原因及修复方法 |
|---|---|
| 切换口型时身体颜色闪烁 | 变体未通过 prep_cels.py |
| 走路或跑步动画忽高忽低 | 不要单独调整绘图大小。同一角色自动共享一个缩放比例。也可以加上 align_head |
| 道具颜色错误 | 调色板条目太接近。移除它或降低 SNAP 值 |
| 说话时嘴巴保持张开 | 双状态口型使用 0.5 阈值。检查音频是否模糊不清 |
| 轻音词嘴巴闭合 | 一个响亮的词设置了该行音量的比例。添加 _m2,或降低该行的 mouth_open_at |
| 听不到雨声或风声 | 环境音默认音量较低。为其设置 level_db,例如 -35 |
| 持续嘶嘶声 | 环境音片段只是噪音。替换它。增益已封顶,因此不会进一步放大 |
| Codex 报告参考图像丢失 | 图像生成必须是它的第一个动作。paint.py 会处理此问题,所以请重新运行它 |
限制
此路线不适用于复杂的战斗、长时间连续动作或写实绘画。