计时台上一名人形模型侧身站立,身体四段分别接出四条测量线,落到下方四只刻度不同的小表盘上,指针停在各自区间内

一、论文方向很多,产品只有一帧

据公开报道,有梳理图形学领域学术会议前沿工作的报道提到,很大比例的论文集中在同一个对象上,也就是人:身体关节的精确驱动、面部微妙肌肉的牵扯、骨骼建模与动画控制、头发物理模拟;另有数字人方向创业公司获得融资的报道。会议名称与融资信息一律按公开报道处理,我们不点任何融资方与金额,也不推断任何方案在画质或性能上的表现。至于具体产品的画面好坏,本文不作评价。

我们从这类信息里只取一个工程事实:研究方向分散在四五个子问题上,而产品端只有一个约束,就是每一帧必须在有限的窗口里画完。以每秒六十帧为目标,单帧可用时间就是十几毫秒的量级,这一点点时间要同时交给骨骼与形状驱动、面部绑定与肌肉变形、次级运动与布料头发、以及渲染与后处理,任何一段超支都要从别的段里扣。所谓”实时数字人难”,难点大多不在某个单项算法做不出来,而在四个都不肯让步的方案没法同时塞进一帧。

因此本文的写法是把这一帧拆成可分配、可测量、可降级的对象。需要先说明一点,这与离线生成视频是两件事:生成式管线管的是内容怎么产出,帧预算管的是一个被驱动的角色在运行时每一毫秒花在哪。也和把世界模型跑在单张卡上不同,那里的瓶颈是显存容纳量,这里的瓶颈是一帧之内的时间分配与抖动。

二、四段预算:一帧里到底在抢什么

我们的分配表按四段建,每段都要写清做什么、在哪里测、成本由什么驱动、超支时先出现什么现象。这张表是交付物的第一半。

段 内容 测量点 成本驱动变量 超支时最先出现的现象
驱动段 骨骼姿态求解、混合形状权重计算、外部驱动信号到关节的映射 输入采样完成到姿态结果可用的时刻 关节数量、驱动通道数、信号延迟与抖动、插值策略 口型与语音错位,头部跟随滞后
变形段 面部绑定求值、肌肉与软组织近似、皮肤滑动 姿态结果写入到网格变形完成 绑定复杂度、混合形状数量、每帧求值次数、是否含物理近似 面部失去细微变化,表情像贴纸
次级运动段 头发的长度与刚度模拟、布料碰撞与自碰撞、附属物摆动 变形完成后到次级运动收敛的这段时间 发束或布料片数、碰撞对数量、子步数、与身体的碰撞是否开启 头发穿模、衣物贴在身上不动
渲染段 蒙皮与阴影、皮肤与毛发材质、透明与反射、后处理与超分 帧提交到实际呈现的间隔,含等待与提交队列 分辨率、光照与阴影数量、后处理链长度、同屏角色数 帧率下降,画面出现整体卡顿

表的读法有两点值得强调。第一,四段之间不是并列的,存在依赖顺序:驱动段的结果是变形段的输入,变形段又是次级运动段的输入。这意味着驱动段的延迟会顺着链条往下推,即便后面三段都很快,端到端的音画同步也已经坏了。很多团队只量渲染段时间,然后困惑于”帧率够高但口型还是慢半拍”,原因就在这里。第二,”成本驱动变量”这一列决定了能不能做预算:关节数、混合形状数、发束数、后处理链长度是团队可配的;分辨率与同屏角色数则由场景决定。可配的那几项才谈得上分配,不可配的那几项只能进触发条件。

至于每一段现实里占多少,我们的答案统一是:需要实测确定。任何外部给出的占比,换一个角色、一套绑定、一个后处理链就失效,抄别人的分配表是最省事也最容易翻车的做法。

三、占比只能自己量:测量口径的六条规定

要让帧预算可讨论,先把测量方法固定下来,否则每次结论都不同。我们按六条规定执行。

第一,测量点成对定义,写明开始事件与结束事件,例如”驱动段”从输入采样完成开始、到姿态结果可被下一段读取结束,不接受”大约在这段时间”。第二,分段计时用同一个时钟源,避免采集线程与渲染线程各用各的时间。第三,不用均值看帧时间,看分布:统计高百分位的单帧耗时与超时帧出现比例,均值会把偶发的长帧抹平,而观感恰恰是被长帧破坏的。第四,测试条件固化并写进报告:同一个角色、同一套绑定、同一个动作片段、同一个镜头运动、同一个场景光照,任何一项变化都要重新测。第五,要区分瓶颈类型:同一份数据要同时看计算是否受限、带宽是否受限、还是提交队列在等待,三种原因的降级动作完全不同。第六,必须跑连续时段而不是一小段,把热降频、后台任务、内存回收带来的漂移计入,观察久跑后帧时间的漂移量与起始值的差距。

预算表里我们还会多记一列”平台档位”,把同一套内容在中档、低档设备上的分布分别记录下来。跨档位的差别通常不是等比例变慢,而是瓶颈换了位置——上一档里次级运动是主要成本,下一档里可能整帧被渲染段占满,此时砍头发不会带来任何收益。这类结论只有按上面的口径重测才能得到。

四、三档实现方式与切换条件

同一件事有三种做法,成本与可控性差别很大,选择依据是”是否可预知”,不是”是否高级”。

预烘焙把结果离线算好,运行时只查表或回放。它最省、最可控,可代价是没法响应实时输入,一旦驱动信号要改变姿态或表情,就暴露出”演不出没排过的动作”的问题。适用于动作集合封闭、镜头固定的场景,比如播报式角色与标准手势。运行时模拟在每帧求解,能响应外部信号与碰撞,代价是成本随场景变化,最容易出现超时帧。适用于必须交互的场景,比如视线跟随、头部对语音的反应、与物体的接触。混合方案是多数产品的实际落点:主干用烘焙或简化求解保证稳定,只在被触发的窗口内启用完整模拟,并为超支准备立即退回路径。

切换条件的写法要具体到”什么时候必须放弃烘焙”:内容需要响应不可预知的输入、需要与场景物体发生可信接触、或者观众会在近景长时间注视某处(此时插值的伪影会被看清),三者任一成立就把这一段移入运行时。反过来,若某段在实测中高百分位成本超过了它带来的观感收益,就应该退回烘焙——这个判断只能来自前面那套测量,不来自审美讨论。

五、降级优先级:先牺牲哪一段

预算不够时要牺牲,问题是被牺牲的顺序。我们的原则是先保”是否像在对人说话”,再保”表情细不细”,最后保”头发和衣服动得对不对”。按观感退化的显著程度排序,从高到低依次是:口型与视线、面部微表情、手部接触、头发与布料。口型错位或视线飘走,观感立刻崩塌;微表情丢失会让角色显得平淡但仍在交流;手部接触穿帮是偶发问题;头发与布料变硬在多数镜头下最不容易被注意。

优先级 先保住的段 触发降级的条件 具体降级动作 恢复条件 验收判据
一 驱动段的口型与视线通道 高百分位单帧耗时连续超过窗口 关闭次级运动与后处理,保留口型与眼动求解 分布回落到窗口内并稳定 音画错位不随负载变化
二 变形段的基础表情 触发一档后仍超时 减少混合形状求值数量与皮肤滑动,保留大表情 有算力余量 关键表情不失真,小表情允许丢失
三 手部接触 近景且手与物体交互 提高接触优先级,把头发与布料降级 退出近景 抓握处不出现明显穿模
四 次级运动段 同屏角色数上升 发束与布料片数减半、关闭自碰撞、远处角色改用烘焙摆动 单角色镜头 远处动作不僵硬即可,不追求可信
五 渲染段画质 以上都不足以达标 降分辨率与阴影,后处理改为轻量替代;保留超分则需单测其成本 帧率恢复 观众能接受画质下降但不能接受掉帧

这张表的要点在第四列。降级必须能自动恢复,否则一次偶发的长帧会让角色永久停在低配状态,而这类”降级后没有回来”的问题在验收里极难发现,只在久跑时才显形。多角色同屏的降级规则也要提前定:按镜头重要度分配预算,而不是所有角色同时降级——后者会让画面整体失去生气。最后一级是形态回退,如果连降级链跑完仍不达标,就明确退回预渲染片段或静态形象,并把它写进产品预期,而不是让用户在卡顿中自己猜。

六、驱动侧约束、共卡冲突与可验收口径

驱动信号侧有三个约束经常被低估。音频到口型的延迟预算是一笔独立的账:从语音输入到口型可见,中间经过识别、映射、求解与呈现,链路长度由产品形态决定,会话式应用要把它当作首要指标盯,不能只盯帧率。动作捕捉数据缺失时的插值策略是第二个,缺数据时要么降频外推、要么回落到烘焙姿态,需要提前定义,否则会出现”没有信号时角色僵住”。跨角色复用是第三个:一个角色上调好的绑定参数与权重范围,换到另一个拓扑不同的角色上往往不成立,把”资产可复用”写进方案前要先验证绑定是否真的通用。

与模型推理共卡时,冲突不体现在平均负载上,体现在时间轴上:推理的峰值与渲染帧落在同一区间就会叠成一次长帧,观感上表现为偶发一顿,而平均值报表里看不到。可用的做法是把两类负载错峰——限制单帧内提交的推理工作量、把批处理拆到多帧、把非关键的推理放到帧间空隙;同时给渲染留出保留时间,宁可推理慢一点。共享带来的显存压力也要单独看,绑定与模拟的数据结构常驻显存,与推理权重竞争的是同一份余量。

验收口径上,我们坚持写客观项而不是主观印象:约定目标帧率与允许的超时帧比例;连续运行一段时长,记录帧时间漂移与是否出现热降频;多角色同屏时按第五节的规则逐级降级并验证能否恢复;音画错位与视线跟随各设上限;失败时回退到什么形态要提前写明,且回退动作本身要能被测到。端侧还是云侧的分工判据也随之清楚:延迟预算紧、互动密集、需要断网可用的放端侧,画质上限高但受设备热与显存约束;重后处理与大规模角色池放云侧,代价是网络抖动直接进入端到端延迟,需要有降级到本地简化的兜底。

洹拓在这类项目里做的是把上面这些做成可执行的东西:预算表按客户的真实角色与设备重测一遍,降级链与恢复条件写成可配置的策略而不是硬编码在渲染分支里,验收项对齐到可复算的数字。我们不承诺”实时电影级”这类说法,也不替任何方案判定画质高低——能给的是每一帧的时间去哪了、超支时按什么顺序让步、以及让步之后能不能自动回来。