简介
这是徐若昊撰写的三篇技术系列博文的最后一篇。该系列博文主要分享《逆向坍塌:面包房行动》背后的声音设计。
- 各位可点此阅读第一篇博文。其中深入探讨了如何利用 Wwise 驱动游戏中的过场动画。
- 各位可点此阅读第二篇博文。其中探讨了如何为倾斜的 2D 俯视视角构建定制的 3D 音频系统以应对衰减上面临的独特挑战。
利用 Wwise Meter 插件实现动画口型同步
技术系列博文 | 第 3 部分
游戏中有很多这样的元素和瞬间,它们的玩法机制是由音频驱动的。借助 Wwise Meter 插件,我们可以实时获取准确的音频数据并回传给游戏引擎,以此来为多个音频系统提供支持。
跟很多其他以动漫为主题的游戏一样,《逆向坍塌》当中有很多剧情对白。其中有一部分在战斗中触发,但更多以 2D 叙事的形式呈现。也就是说,屏幕左右两侧的角色会进行问答式的对话。
上图举例展示了游戏中的 2D 叙事机制。在截图的时候,角色 Mendo 正在说话。在触发语音的时候,会在角色头像之上播放口型动画。该功能由从 Wwise 获取的 Audio Volume 数据驱动。
游戏可利用 Audio Volume 数据将口型动画与语音同步,从而增强玩家跟角色互动时的沉浸感和临场感。这样叙事体验会更有层次,从而给玩家更强的代入感。
为了实时获取 Audio Volume 数据,我们使用了 Wwise Meter 插件。这个插件不仅易于使用,而且非常高效,可将 Wwise 中的音频数据发给游戏引擎。下图显示了主语音总线上的 Wwise Meter 设置。
在 Wwise Meter 插件内部,我们将 Speech_MeteringData RTPC 与之关联以将数据回传给游戏引擎。此 RTPC 会捕获在游戏中触发语音时产生的输出音量信息。我们将值限制在了 -48 ~ 0 之间,用以表示 Audio Volume 电平的范围。在语音音量达到峰值时,该值可能会超过 0。不过,在典型混音设置下最好避免这种情况,确保数值始终在 0 以下。
通过设置此配置,我们可以根据需要准确捕获 Audio Volume 数据,并将其传给游戏引擎,以此实现各种玩法机制。
上面的段落总结了 Wwise 端的设置。要在游戏引擎端使用这些数据,我们只需添加几行代码来检测音量范围,并将该数值转换为动画系统可用的数据。这里的动画代码写得比较简单,纯粹为了演示,因为每个游戏都会采用不同的动画系统或插件。
我们的游戏没有复杂的动画系统,角色的嘴巴只有 Open 和 Closed 两种状态。所以,我们可以直接使用三元条件运算来判断是否要让说话的角色张开嘴巴并做相应的动画处理(有关 GetGlobalRTPC() 的实现,请参阅前面的段落)。
bool bIsCharacterMouthOpen = (GetGlobalRTPC(“Speech_MeteringData”) > -48.0f && GetGlobalRTPC(“Speech_MeteringData”) <= 0) ?true : false;
对于很多其他游戏(尤其是 3D 游戏),角色的骨骼绑定中可能包含关节和骨骼。对此,我们可以对动画设计师用于改变嘴巴开合程度的关节角度进行调整。该值通常用浮点数表示。比如,假定可通过 speakingCharacter.SetMouthOpenness(float mouthJointAngle) 获取该值,则嘴巴开合程度在 0 ~ speakingCharacter.MaxMouthOpenness() 度之间。
在本例中,我们要创建一个小型封装函数,以便提取参数修饰符的输出值,并根据需要在相应区域应用该值。
public float GetGlobalRTPC(string rtpcName)
{
int rtpcType = 1;
float acquiredRtpcValue = float.MaxValue;
AkSoundEngine.GetRTPCValue(rtpcName, null, 0, out acquiredRtpcValue, ref rtpcType);
if(acquiredRtpcValue >= 0.25 && acquiredRtpcValue <= 16)
{
return acquiredRtpcValue;
}
else
{
return 1.0f;
}
}
除了对 RTPC 做全局设定,上述函数还会确保在检测到错误的值时忽略要设置的 RTPC 并重置为默认值 1.0f。
在这种情况下,我们可以使用以下函数来对上述代码进行优化以支持此功能:
public float SetMouthOpenessByWwiseAudio()
{
float mouthOpennessToSet = 0.0f;
float retrievedMeteringRTPCvalue = GetGlobalRTPC(“Speech_MeteringData”);
if (retrievedMeteringRTPCvalue > -48.0f && retrievedMeteringRTPCvalue <= 0)
{
mouthOpennessToSet = speakingCharacter.MaxMouthOpenness() * Normalization(retrievedMeteringRTPCvalue, -48.0f, 0.0f));
}
speakingCharacter.SetMouthOpenness(mouthOpennessToSet);
}
当然,该函数会根据从 Wwise Meter 插件接收的 Audio Volume 数据准确设置嘴巴开合程度。这样可以确保口型动画与 Audio Volume 精确同步。
免责声明:本文中使用的代码段都是重构的通用版本,仅用于演示目的。其底层逻辑经验证可正常运行。不过为避开潜在的版权限制,示例中省略了特定于项目的 API 调用和函数。
评论