山东大学项目实训个人纪实(6)——降低唇形同步性能需求
在上一阶段我虽然通过全内存流式传输将纯语音的对话延迟降低到了较为理想的水平但另一个棘手的问题又浮出了水面——唇形同步的性能消耗过大。之前项目中采用的 Audio2Face 方案依赖深度学习算法需要调用 GPU 来实时计算口型。这导致系统对硬件配置的要求极高在我平常使用的笔记本上甚至根本带不动。为了能让这个医患沟通评价系统在更普及的硬件如普通 CPU 平台上流畅运行我不得不寻找一种低开销、低延迟的唇形同步替代方案。经过权衡我决定重新调转方向去攻克之前暂时搁置的 Oculus Lipsync 方案。1. 重新审视 Oculus Lipsync虽然 Meta 官方早已经停止了对 Oculus Lipsync 插件的维护且原版插件根本不支持新版的 UE5.6原设计主要用于离线动画烘焙但它的核心算法依然具有极高的应用价值。它的底层逻辑很纯粹直接实时分析音频的波形计算出 16 种“音素Visemes”的权重。如果我们能够利用 C 把这些计算好的权重实时提取出来并直接映射到 MetaHuman 的面部曲线上就能实现一个几乎不占用 GPU 的、超低延迟的纯 CPU 唇形同步方案。为了解决版本兼容问题我从 GitHub 社区中找到了由其他开发者维护的 UE5 增强版分支。在将项目转为 C 后我把这个插件引入并重新进行了编译。折腾了一番终于让它在我的 UE5.6 开发环境中顺利加载并运行了起来。2. 核心难点将音频流切片传入插件插件计算音素的核心是调用 FeedAudio() 函数。由于其底层的 ProcessFrameAsync() 是逐帧进行异步分析的而我们的音频是连续的输入流因此不能直接把整段音频塞进去必须在前端对音频数据进行精细的切片。为了做到音画同步我需要根据渲染帧率来计算每一帧应该传递的数据量。假设系统运行帧率为 30 fps即单帧时间约为 1/30 秒我们的音频参数为采样率 24000 Hz单声道16-bit占 2 字节。那么每一帧需要塞给插件的数据量计算如下通过编写一个辅助函数我让系统以每帧 1600 字节的速率源源不断地向插件输送音频切片。实践证明这种方式确实能让音素权重的计算与画面渲染保持同步。3. 如何用音素权重精准驱动 MetaHuman拿到实时计算出的 16 种音素权重后如何让 MetaHuman 的面部做出相应的口型成了下一个需要攻克的点。在新版的 UE 中MetaHuman 的面部蓝图结构发生了一些调整。我摸索并对比了两种驱动方案方案一利用 Control Rig 驱动我尝试引入了 MetaHuman 的头部控制组件 CR_MetaHuman_HeadMovement_IK_Proc。这个方案的设计思路是通过面部绑定控制器在代码中直接修改面部 51 个控制点对应的曲线值。但在实际编写代码时我发现这种方式异常繁琐。只用 16 个音素权重去联动驱动 51 个控制点映射逻辑非常复杂而且这种“非直观”的代码修改方式对于后续负责细节微调的美术同学来说较为不友好极难进行后期调试。因此我放弃了这条路线。方案二利用姿势资产Pose Asset驱动最终采用既然直接改控制点太痛苦我便转向了官方提供的 ARKit 姿势映射资产 PA_MetaHuman_ARKit_Mapping。这个资产包含了烘焙好的 ARKit 标准面部姿势最关键的是它支持“姿势混合Pose Blending”。这意味着我可以很直观地在引擎里为 Oculus 的 16 种标准音素分别设立一一对应的标准唇形。在动画蓝图中我只需要使用 Modify Curve 接口将插件算出来的音素权重实时赋给这些曲线就可以非常直接地融合出各种过渡唇形。这种“所见即所得”的交互方式也大大降低了美术团队调试的门槛。4. 现状与后续进展目前这套基于 Pose Asset 驱动的纯 CPU 实时唇形同步方案已经在我的本地测试环境中跑通了原型整体运行较为流畅性能占用也大幅降低。这初步验证了方案的可行性至少笔记本电脑不再像之前运行 Audio2Face 那样吃力了。接下来我的重心将转移到视觉效果的打磨上。这周我会配合美术团队针对这 16 种标准音素逐一去精调对应的面部与唇部姿势优化口型之间过渡的自然度争取让最终呈现的虚拟人对话体验能够有更进一步的提升。