圆窗试片完成以后,我遇到一个看起来很小、实际上会影响整套视频的问题:人物已经叠在动画上,字幕应该放在哪里?最省事的做法,是把字幕固定在底部正中。它容易实现,也容易在一张截图里看出“没有压到圆窗”。但画面一换,人物位置、字幕长度和动画里的文字都会变化,这个坐标就不再可靠。
我一开始也把注意力放在“这一帧看起来有没有挡住”上。后来重新想了一遍,发现真正要解决的不是某一张截图好不好看,而是字幕和人物叠加以后,版式有没有一条能够持续执行的边界。只要边界说清楚,人物换位置、台词变长、画面换动效,规则仍然能工作。
先处理一次试片里的不舒服
当时的画面是横屏动画加圆形人物小窗。圆窗不是固定在画面中央,而是根据人物的视线和构图,放在左下角或右下角。动画本身有自己的排版,字幕也不应该为了迁就圆窗而完全改成另一套布局。
最初的方案把字幕固定在底部居中,并给圆窗留出距离。这样做有两个直接好处:实现简单,检查也直观。字幕有一个固定坐标,圆窗有一个固定避让区域,两者只要不重叠,试片看起来就能过关。
但我越看越觉得不对。固定底部正中,等于把原本属于字幕系统的纵向排列硬编码成一个位置。原生排版可能会根据句子长度、行数和画面节奏调整,而固定坐标只记住了这一次试片的结果。一次试片里看起来稳定的坐标,不等于可以迁移到所有人物和所有台词。
如果不处理这个问题,后面会出现两种麻烦。第一,人物靠近画面右侧时,字幕可能向右延伸,遮住脸或视线。第二,字幕变成两行以后,包围盒变高,底部固定位置会压到圆窗或动画中的关键文字。到那时,每换一个人物、每换一段文案,都要重新打开画面手工调一次,所谓自动化只剩下批量生成,判断仍然靠临场记忆。
固定坐标为什么会失效
这里最容易误判的是,把“字幕不要挡脸”理解成“字幕放在一个通常不会挡脸的位置”。通常不会发生,不代表一定不会发生。人物的位置是动态的,字幕的宽度也是动态的,画面边缘还会限制字幕能够移动的范围。
可以把每个对象先看成一个矩形边界。人物区域有左、右、上、下 4 个边界;字幕包围盒也有 4 个边界;屏幕安全区同样有自己的左右上下界。圆窗只是人物区域的一种呈现方式,并不会改变这个判断。我们关心的不是圆形看起来多大,而是它在屏幕上实际占了哪一块空间。
这样一来,问题就从“这张截图里字幕放哪儿好看”,变成了几个可以检查的问题:字幕的右边界有没有越过安全区?字幕包围盒有没有和人物区域发生碰撞?如果发生碰撞,向左移动以后是否仍然满足左侧安全边距?如果不能同时满足,就要知道是字幕太长、人物太靠边,还是这个镜头本来就不适合当前布局。
表面上我是在处理字幕位置,其实我是在处理一个叠加系统的边界关系。这个转换很重要,因为视觉判断适合发现问题,几何约束才适合把问题交给后续流程重复执行。
保留原生排版,再做最小位移
用户对这次调整的要求很明确:不要因为圆窗,就把原生的纵向排列整体推翻;字幕可以保持原来的上下关系,但不能太靠右,也不能压住人脸。这个要求看似在限制实现,实际上给了一个更稳的优先级。
我选择“先排版,再避让”,是因为原生排版承担了阅读节奏,避让只应该解决碰撞。若一开始就把字幕锁死在底部中央,排版系统失去了根据内容变化的空间;若一开始就为了人像重新设计整套字幕,改动范围又会扩大,后续所有视频都要承担这个额外规则。
具体流程可以这样理解:先让字幕按照原生规则生成,得到一个初始包围盒;再读取人物在当前画面中的区域;然后检查字幕右边界是否进入人物区域,或是否超过屏幕安全区。如果没有碰撞,保持原位置。如果发生碰撞,只沿水平方向向左移动,移动量取“刚好脱离碰撞所需的最小距离”,同时不突破左侧安全边界。能用一条边界规则解决的问题,就不要用一批截图记住例外。
避让的目标不是把字幕放到某个预设点,而是让它在满足约束的前提下尽量少动。
这条规则保留了两个好处。第一,人物在右边时,字幕可以自然往左让;人物在左边时,字幕没有必要被无条件推到另一侧。第二,字幕长度变化只会改变碰撞计算的结果,不会把整套版式改成另一种风格。规则的核心不是“字幕永远在左边”,而是“只有碰撞时才移动”。
截图能发现问题,却不能承担规则
讨论中曾经考虑过另一条路:先出截图,再通过截图判断字幕有没有挡住人物,必要时逐张调整。这条路不是完全无效。截图适合做最后的视觉抽查,能发现边界模型没有覆盖的特殊情况,比如动画自带的细小文字、人物头发超出预估区域,或者某个镜头的构图本身就很拥挤。
但我最后把“截图决定字幕位置”删掉了。原因很简单:截图记录的是结果,不是产生结果的条件。下一次人物换了位置,截图就失效;字幕换了长度,原来的调整也失效;如果再把人工调整保存下来,保存的其实是一批互相依赖的例外。
最容易误判的错误捷径,就是把人工看过一次当成规则已经成立。它会让我们获得短暂的安心,却没有回答边界变化以后怎么办。如果不改掉这条捷径,工作量会随着镜头数量线性增加,维护成本则会随着例外数量一起增长。更麻烦的是,人工调过的坐标很难解释,后来接手的人只知道“这里要往左一点”,不知道触发这个调整的条件是什么。
我不是完全放弃截图,而是把它放回合适的位置:几何规则负责定位,截图负责抽查。这样既保留了视觉验收的价值,又不让截图成为每次生成的前置依赖。一个流程成熟的标志,不是它完全不需要人看,而是人看的时候是在验证边界,而不是替系统逐帧做决定。
用边界测试代替单张回归
有了边界以后,验证也应该换一种方式。不能只拿圆窗放在一个角落的试片看一遍,就宣布字幕不会遮挡。至少要构造几种会改变边界关系的情况:人物靠近左侧、人物靠近右侧、人物在中间;字幕较短、刚好两行、明显偏长;人物区域较小和较大;屏幕安全区较宽和较窄。
测试的重点不是每种组合都截一张漂亮图片,而是检查几个不变量。字幕不能越出安全区;发生碰撞时,向左移动后必须消除碰撞;没有碰撞时,字幕不应该被无故挪动;左移受到边界限制时,流程应该明确报告“当前布局无法同时满足”,而不是悄悄把字幕压到画面外。
这里还要保留一个失败边界:如果人物区域已经占据了右侧大部分空间,字幕又长到无法在左侧安全区内容纳,那么单靠移动解决不了问题。此时需要缩短文案、调整字号、改变镜头构图,或者允许换一种布局。把这种情况当成“再多左移一点”只会把问题推到屏幕边缘。
我判断这种验证比截图回归更值得沉淀,是因为它检查的是规则的性质,而不是某一次渲染的外观。截图仍然可以帮助我们发现审美问题,但边界测试能够证明:人物和字幕换了输入以后,系统是否仍然遵守同一组约束。
下次我会怎么做
下次遇到人物叠加和字幕避让的问题,我会先问 3 件事:人物区域如何表示,字幕包围盒如何得到,屏幕安全区的边界是什么。没有这 3 个量之前,我不会先讨论“往左一点还是往右一点”,因为那仍然是在凭感觉保存坐标。
然后我会把布局拆成 2 层。第一层保留原生排版,负责行数、纵向关系和阅读节奏;第二层只负责碰撞检测和最小位移,负责把字幕从人物区域和屏幕边缘让开。两层职责分开以后,换人物不需要重做排版,换台词也不需要重新手调每个镜头。
最后,我会用不同人物位置和不同字幕长度做边界测试,再用少量截图做视觉抽查。这样形成的不是一张“正确截图”,而是一条可以迁移到后续视频的规则:先计算,后避让;先保留原生排列,再做最小改动;无法满足约束时明确暴露问题,不用一个看似正常的坐标掩盖它。
这件事让我重新意识到,版式的稳定不是把所有东西固定住,而是把哪些东西可以动、什么时候动、最多动到哪里说清楚。真正难的不是让这一帧看起来不挡脸,而是让下一次换一个人、换一句话、换一个动效时,系统仍然知道应该怎么做。