本节摘要:本节解决生成段的两个控制问题:画面锚定与镜头语言。画面锚定的主力是图生视频:给首帧,画面的构图、主体、风格就锁死在图上,模型只负责「让画面动起来」;再给尾帧,连落幅都锁定,两帧之间由模型补全运动——首尾帧组合是流水线上确定性最高的生成方式,首帧从文生图(便宜、可反复挑)或上一镜头的尾帧(天然的镜头衔接)来。镜头语言靠提示词词表:推、拉、摇、移、跟、固定六个动词加修饰语,把分镜的 camera 字段机械翻译进 prompt,不临场发明写法。最后是多镜头一致性——同一主角在不同镜头里变脸是生成分散采样的必然产物,工程上有四类缓解:设定卡统一描述、参考图复用、固定种子、转场遮挡;都是缓解不是根治,根治要等模型与原理侧的进步,《多模态大模型》第 8 章第 8.3 节讲的长时序一致性研究是这个方向。
只给首帧 首尾帧都给 ┌────────┐ ┌────────┐ ┌────────┐ │ 首帧图 │ ──模型自由发挥──▶ 动起来 │ 首帧图 │ ──模型补运动──▶ │ 尾帧图 │ └────────┘ (落幅不可控) └────────┘ (起与落都锁定) └────────┘ │ │ ▼ ▼ 适合:氛围空镜、 适合:有明确落幅的镜头、 结果可多方案挑拣 需要与下一镜衔接的镜头
首帧从哪来是流水线的真问题,三条路径各有位置。文生图挑图:先出图再出视频,图便宜视频贵,挑图阶段把构图、主体、风格都定下,视频段只花一次钱。上一镜的尾帧衔接:镜头 101 的尾帧抽出当 102 的首帧(ffmpeg 一条命令抽帧,第 5.1 节),两个镜头的空间连续性有了保底。素材图改造:授权素材或程序生成的图形(第 5.3 节 HTML 渲染的帧)作首帧,适合信息可视化内容。
把「尾帧衔接」放进彩虹片场 2 走一遍(镜头 201 到 203,示意编号)。这三个动画镜头空间上连续:阳光飞向水滴、光进入水滴折射、光散开分色射出。生成顺序因此不是乱序提交,而是链式推进——201 的尾帧喂给 202 当首帧,202 的尾帧再喂给 203:
# chain_diagram —— 场 2 三个镜头的链式生成结构(示意) 文生图挑图 201 片段 │ 首帧 │ 抽尾帧 ▼ ▼ [201 任务] ──▶ shot_201.mp4 ──▶ [202 任务] ──▶ shot_202.mp4 ──▶ [203 任务] │ 链内空间连续,链外各自独立
# bash —— 抽 201 的尾帧作 202 的首帧(结尾留安全余量,命令族见第 5.1 节) ffmpeg -ss 3.8 -i build/04_clips/shot_201.mp4 -frames:v 1 -q:v 2 build/03_assets/f202_first.png
两个工程细节。其一,抽帧位置留安全余量:紧贴片段末尾抽,容易抽到淡出的半透明帧,拿它当下一镜的首帧,开头会莫名发虚——示意片段总长 4 秒,抽帧点放在 3.8 秒而不是 4.0 秒。其二,链式推进牺牲并行度:链上的任务只能串行,所以链不宜过长,同场三四个镜头成链、跨场就断开各自独立,把并行机会留给链与链之间。
运镜写法忌临场发挥——同一个「推」今天写 push 明天写 zoom in,回归对比就废了。固定一张词表,分镜段与生成段共用:
| camera 值 | 提示词写法(中英任选其一并全片统一) | 适用 |
|---|---|---|
| 推 | 缓慢推近,镜头向主体推进 | 强调主体、收束注意力 |
| 拉 | 缓慢拉远,远离主体 | 交代环境、收尾 |
| 摇 | 左摇(或右摇),机位固定 | 展示全景、跟随视线 |
| 移 | 横移跟拍 | 行走、流动感 |
| 跟 | 跟随主体运动 | 动线镜头 |
| 固定 | 固定机位 | 特写、稳定叙事 |
# camera_to_prompt.py —— 分镜字段到生成提示词的机械翻译 CAMERA_PHRASES = { "推": "缓慢推近,镜头向主体推进", "拉": "缓慢拉远,镜头远离主体", "摇": "水平摇镜,机位固定", "移": "平滑横移", "跟": "跟随主体运动", "固定": "固定机位", } def build_video_prompt(shot, style): parts = [shot["visual"], CAMERA_PHRASES.get(shot["camera"], "固定机位"), style] return ",".join(p for p in parts if p)
翻译是纯机械的,没有一步「让模型自由理解」——可控性来自把裁量权从生成时刻挪到分镜时刻,这正是 2.3 节人审关卡审过的东西原样落地。
同一主角在镜头 101 与 102 里「换了张脸」,原因是结构性的:每个镜头是独立采样,模型没有跨镜头记忆。工程缓解四板斧,按见效顺序:
| 手段 | 做法 | 局限 |
|---|---|---|
| 设定卡 | 主角的外貌、服装、色调写成固定描述块,拼进每个 prompt | 只约束语义,采样仍会漂 |
| 参考图 | 主角定妆图作为图生视频首帧或参考输入 | 需供应商支持参考图能力 |
| 固定种子 | 同主角镜头用同种子族(同种子加微扰) | 供应商不支持种子时失效 |
| 转场遮挡 | 一致性最险的切换点用叠化、黑场、局部遮挡 | 是剪辑层面的遮丑,不是解决 |
务实的目标管理:四板斧齐上,主角能达到「观众认定是同一个人」的水平,达不到「逐帧像素一致」。所以分镜阶段就要为一致性设计——同场镜头尽量共享首尾帧链,跨场切换安排在转场处,别把「同一张脸的特写对切」写进分镜自找麻烦。
设定卡是四板斧里性价比最高的一张,值得看一个实体。它是一小块固定的 JSON,描述块逐字拼进每个含主角的 prompt:
# character_card.json —— 主角设定卡(示意,拼进每个含主角镜头的 prompt) { "name": "林小满", "look": "二十五岁上下,齐肩黑发,深蓝工装外套,米色围巾", "palette": "暖色调低饱和,柔光", "keep": "以上外貌要素在所有镜头保持一致,不得增删配饰" }
两条使用纪律。其一,描述要可核对:齐肩、深蓝、米色都是看图能打钩的词,「气质沉稳」这种没法核对的词不进卡。其二,卡要短:设定卡每个含主角的 prompt 都要背一遍,卡越长,真正要紧的特征被稀释得越快——十行以内是舒适区(工程口径)。设定卡与 6.1 节(后半本)的音色映射表是同一个思想:角色的一致性,先在数据里锁一次,再谈生成。
生成段开工前的最后一步是把 shots 翻译成任务清单(素材段的输出之一,第 4 章补首帧来源):
# build_tasks.py —— 分镜 JSON 到生成任务清单(写法示意) import json def build_tasks(board, style): tasks = [] for shot in board["shots"]: task = { "shot_id": shot["shot_id"], "mode": "i2v" if shot.get("first_frame") else "t2v", "prompt": build_video_prompt(shot, style), "duration": shot["duration"], "seed": shot.get("seed"), } tasks.append(task) return {"schema_version": 1, "tasks": tasks} with open("build/02_storyboard/approved_board.json", encoding="utf-8") as f: board = json.load(f) tasks = build_tasks(board, "温暖手作感,暖色调")
mode 字段区分两类任务:i2v(图生视频)带首帧,t2v(文生视频)纯文本。清单是生成段与素材段的对接口——素材段负责把每个 i2v 任务的 first_frame 路径填上,填不上的降级为 t2v 并打标记,生成段照单执行。
| 症状 | 根因 | 处置 |
|---|---|---|
| 首尾帧之间画面剧烈闪变 | 两帧内容跨度超出模型的补全能力 | 拆成两镜,或中间再补一张关键帧 |
| 给了首帧,画面却「不像图」 | prompt 与首帧冲突,模型两头为难 | prompt 只写运动与氛围,构图让位给首帧 |
| 抽出的尾帧发虚或半透明 | 抽帧位置紧贴片段末尾,抽到淡出帧 | 抽帧点前移零点几秒,留安全余量 |
| 运镜词写了画面没动 | 供应商对该类提示词支持有限 | 对照官方提示词指南;改用首尾帧差异表达运动 |
| 同种子族微扰后风格漂移 | 扰动幅度过大 | 缩小微扰幅度,或回归参考图锚定 |
排查这类问题先分清两种病因:「约束没生效」还是「能力不支持」。前者查自己的链路——设定卡有没有真的拼进 prompt、首帧有没有真的带上请求;后者换手段——提示词表达不出的运动,改用首尾帧差异去表达。把病因分类完再动手,能少走一半弯路。
云上调用与控制手段齐了,下一节看另一条路——LTX-2 等开源模型搬回本地跑,什么时候划算、要什么硬件。