前言
在游戏音频开发的世界里,我们常常面临这样的挑战:你刚刚搭建好一个全新的 Wwise 项目,准备进行 boss 战的实机测试,却发现现有的游戏管理(GM)命令并不如预期般便捷。
你的账号等级太低,无法直接进入特定关卡的 boss 战?没关系,从头开始闯关。
但当你以开挂的方式快速击败 boss,却发现 boss 的技能还没完全展示?没关系,找游戏策划调整数值。
最后,你发现某个大招难以复现,因为它的操作门槛太高……(让游戏程序更新 GM 命令需要排期,而你等不及……)
最终,你只能依靠短暂的战斗记忆来调整项目中的各种问题。
还有更多令人头疼的情况:进行大型测试时,服务器只允许一次测试机会; 测试多人战斗时,人手不足,只能测试一两次; 等等……
可不可以像电影一样,把游戏流程录制成 Wwise 声音胶片存起来,以后可以无限次回放呢?
当然可以,我们尝试开发了 URW(unity-Reaper-Wwise)回放工具链,只需将一次流程录制下来,就可以生成一个 Reaper 工程,在 Reaper 中触发 Wwise event,满足之后无限次的联调与测试。
生成的 Reaper 工程就是独属于你的 Wwise 声音胶片,在 Reaper 这个放录机上,你可以自由回看自己的胶片,这样,Wwise 就成为了 Reaper 的混音台,允许声音设计师反复打磨声音表现。
此外,将游戏流程录制成声音胶片(Reaper工程)还意味着,设计师可以在工程中随意调整播放进度,定位到游戏流程的某个特定时间点,针对某一帧或某一小段游戏流程反复打磨。
图 1 - 工具链流程图
视频 1 - 工具链演示视频 Unity-Reaper-Wwise
第一步:Unity 录制音频信息
既然是回放 Wwise 的声音,那么这部分需要回放的声音数据。数据形式是什么?声音数据该怎么抓取?
关于数据形式
因为是 1.0 版的工具流,所以当前的数据形式还比较简单。一句话来说,只是知道在什么时间?播放了哪些声音事件即可了。如下图。
图 2 - 数据形式
关于数据抓取
前期思考过两种抓取方式:
1、Unity runtime 阶段嵌入抓取逻辑。
这种方式我们构想的理想实现方法是:项目中所有的播放声音行为有一个统一的入口。然后在这个入口处嵌入抓取逻辑,来一个声音,便抓取一个声音,存储一个声音。但考虑到不同的项目有不同的逻辑,或许就有项目不会有这样的统一的播放入口。我们给这套工作流的首要要求就是通用性,即做到任何项目都可拿来即用。因此如果后续存在在不同的项目去改造逻辑适配这套工作流的情况,这是不可接受的。另外,我们要求可以在Editor模式下也可使用。最后,在实现层面还有一个尚未验证的担忧,考虑到游戏跑起来之后的时间稳定性,或许会导致本该是同一时间触发的声音,最后数据记录下来的时间数据有所差异。所以,综上我们采用了以下第二种抓取方式。
2、Waapi
Waapi 中有一个订阅接口:ak.Wwise.core.profiler.captureLog.itemAdded
这个订阅函数会在新的日志条目添加到 Wwise 中时,执行你定义的回调函数。我的处理是在这个时候存储新的条目的信息,然后在录制结束之后,通过另外一个函数将条目信息列表生计算出所需的可供播放的数据。
需要注意的是
- Wwise 条目时间单位是毫秒,且存在同一时间触发多个 event 的情况。因此,不管是在存储还是在播放都应该针对这个做出相应的应对操作。
- Wwise 条目时间是声音引擎初始化开始所经过的时间,因此有可能录制的第一个数据触发时间量级很大。(或许你在声音引擎初始化了 1 小时之后才开始录制,那么第一个声音数据的时间就要 >=60*60*1000)。所以,不管是为了录制完成之后及时回放,还是为了把录制的数据能在后续生成的 Reaper 工程中能顶头播放,都应该把所有的数据时间等比例前移,我选择的做法是将所有的时间统一从 0 秒或 0.5 秒处开始。
其他便是播放的时间控制逻辑、用户界面的逻辑以及保存加载逻辑编写了,这里不作过多展开。
第二步:Json to Rpp
在生成 rpp(即 Reaper 工程)这一环,我选择了用 Node.js 来编写脚本。因为对于技术音频来说,我认为基于 Node.js 的 JavaScript 语言是一种相对来说比较轻量级的选择,可以快速地达到“写工具”的目的,从而将更多的时间用在“设计”上。
首先,Node.js 有 npm 包管理工具,可以将脚本所需的依赖包粘合在一起,使脚本开发过程变得相对流畅。比如 FFmpeg 是一个非常强大的音视频处理工具,支持多种音视频格式,提供了丰富的功能和参数选项。而在 Node.js 中使用它也相对便携,只需使用 npm 命令进行安装:
Plain Text |
安装完成后,就可以在 Node.js 代码中引入 fluent-ffmpeg 模块,然后使用其提供的 API 进行音视频处理了。在我之前给音频部写的打 metaData 标签的工具中,也是调用了 FFmpeg 中相关的 API:
图 3 - npm 中的 FFmpeg Metadata API 示例
相比于其他编程语言,Node.js 在处理 IO 密集型任务上表现更为优异,这意味着 Node.js 脚本能够更快地读取和写入大量的音频数据,而不会因阻塞而导致程序运行缓慢。另外,Node.js 还提供了异步编程模型,可以使脚本在进行 IO 操作时不会阻塞主线程,从而保持应用的高响应性。
更加令人惊喜的是:JavaScript 有相关的 Waapi 接口,你可以在网页中、桌面应用程序中和 Wwise 做相关的交互。这也为技术音频在设计工作流的过程中提供了很多的思路。通过 Waapi 接口,可以方便地使用 JavaScript 与 Wwise 进行通信和交互,实现对音频资源的实时控制、管理和自动化处理。例如,可以通过 Waapi 接口实现动态更改音频事件、创建和管理游戏中的声音对象等操作,从而为游戏音频设计提供更多的可能性。
图 4 - 官方用 JavaScript 写的“Hello Wwise” Waapi 示例
在当前这个回放器工具中,我就是通过 Waapi 来获取实践中音频样本的最大长度,从而将其转换为 rpp 中 item 的长度的。我使用的 uri 是 ak.Wwise.core.object.get,options 为'maxDurationSource',以 WAQL 的形式向 Wwise 发送 http 请求,从而获取信息。
图 5 - 使用 Waapi 的查询事件信息函数
至此,结合 Unity 中录制的 Json、mp4 和从 Wwise 获得的信息,我已经能完完全全地生成一个 rpp 的文本文件作为这个工作流中的 Reaper 工程了。
图 6 - rpp 文本信息对应
第三步:Reaper to Wwise (ReaWwise Caster)
图 7 - ReaWwise_Caster UI 界面
概述
在 Reaper 端实现重放的初衷,是为音频设计师提供一个能够在 DAW 中配合视频调试 Wwise 工程的环境;更加贴合 DAW 使用者的操作习惯,播放方式能够与制作视频贴片时的播放方式相同。
我把脚本设计成小 UI 的形式,相当于是个小遥控器——开关开启,遥控器丢在一边就不用管了(当然报错了还是要管一下 0 0)。
为了实现这个设计目标,工具需要实现这些功能:
- 基于播放光标位置捕捉 item 的 event 触发器
- 连接 Waapi 并调用 API 的通道
- 播放视频的同时低延迟 post event
- 操作者自由开启或关闭 capture 功能, 无感化 Wwise 通信
前置扩展
ReaWwise 是 Wwise 中的一个插件,它允许用户将 Reaper 中的音频和音乐资源集成到 Wwise 中,以便在游戏中使用。因此,ReaWwise 插件提供了一些 API,用于在 Reaper 和 Wwise 之间进行交互,开发人员可以将 Reaper 中的音频资源快速有效地转换为 Wwise 项目,并在游戏中使用它们。
图 8 - 前置扩展 1
图 9 - 前置扩展 2
Reaper 端 Waapi 调用的实现
今年一月份 AK 官方扩展了 ReaWwise 的功能,提供了在 ReaScript 调用 Waapi 的 API:
图 10 - 官方使用 ReaScript 编写的示例脚本
相关 API:
Lua |
使用 ReaScript 相关API,可收集 Reaper 中 item、track 所包含的相关信息,最终通过 reaper.AK_AkJson_Map_Set() 转化为调用 ak.soundengine.postEvent 所需要的格式。
基于播放光标位置捕捉 item 的 event 触发器
由于 ReaScript API 中没有提供捕捉 item 的 trigger 功能,所以只能自己写啦。基本思路是收集各轨道 item 起始位置数据,实时刷新播放光标位置坐标,当判定与起始位置重合时,post event;
然而在实际码代码时遇到两个问题:刷新函数时间间隔(用 while do 秒崩)、判定点精确度。
在献祭头发后,问题解决:
- ReaScript 中提供每帧刷新函数,运行流畅没烦恼。
Lua |
- 为了保证声音播放的准确性,将起始位置精确到1ms,以兼顾延迟和判定的准确度。
后续功能展望
打通 Reaper-Waapi 通道意味着,Reaper 中更多的参数可转化为 Wwise 相关参数,实现 Reaper 控制 Wwise 播放行为的目标。我们希望最终可以实现的是 Wwise 可以作为 Reaper 的拓展辅助调音台。功能展望:
- 轨道包络控制 rtpc
- Item 控制 switch、state 切换
- 为轨道分配 GO,根据 Unity 回放器记录数据,实时更新 GO 坐标信息
- 结合 ReaWwise 原生功能实现 Reaper item、Wwise audio clip 无感化自由替换,实现在 Reaper 中还原 Wwise 中听感并直接挂插件调整素材,一键导回 Wwise 工程
鸣谢
感谢幕后@张成功的鼎力支持,Unity 端信息抓取链是由他开发完成,在开发过程中帮助我们解决了超多难题。文章作者本应有他,然而他只想做一个隐藏在黑暗中的扫地僧~
评论