这篇文章转载自社区资深开发者 YAZONE,团队面向 Apple Vision Pro 平台,从视觉特效入手,尤其针对音乐可视化进行了一场数字音乐表演的探索。点击阅读原文,前往 YAZONE 的 Unity 中国开发者社区主页,阅读更多干货文章。作为一个游戏研发背景的技术团队,随着 Apple Vision Pro 的上线,我们关注到在这一新情境下沉浸表现的潜能,以及空间计算所蕴藏的巨大想象力。历时一个月的敏捷开发,一场以 VFX 为切入点,目的为测试和压榨其机能的预研发就此展开。为了充分提炼 full immersion 模式下的沉浸感特性,数字音乐表演成为了这次的预研发选型。不同于常规的移动端开发,vision pro 凭借其性能上的巨大优势,让开发小组就效果的潜力摩拳擦掌。由于此前开发的工具已经具备了角色及部分主题场景 UGC 的基础,单独的材质移植测试也做过两轮,综合下来使得资产部分的压力相对较小,留给 VFX 的空间就显得特别美妙了。于是组内一拍即合,既然是踩坑测试,找准方向后就最大程度尽情试错。 考虑到 VFX 开发环境的支持和渲染效果,在 vision OS 原生与 Unity 引擎中我们选择了后者并采用 URP 渲染管线。主要原因得益于之前 Unity 的开发经验积累,允许我们的小组在有其他并行任务的同时,快速搭建起开发框架并且进行尝试,以达到用快速验证的方式进行敏捷开发,在验证中建立流程形成标准。当然,测试的重心特效部分也遵循这个方法,于是便迎来了第一步,也就是进行技术选型的关键测试。
这是除去单一主题测试外,小组第一次在 AVP 平台进行全流程开发,无法仅凭借苹果官方公布的硬件数据和一些机构的主观评测,去推导我们想做的内容。资料有限,需求需要进一步明确。即:支持哪些?支持多少?为了细化这个问题,我们进行了一个复杂 PBR 材质场景压力测试,反推出:同屏三百多万面,两百多个 batch,至少 1024 贴图,运行 40~60 帧。明确了这样一个范畴之后,VFX 设计师所关心问题的测试也在逐步进行中: 是否支持 VFX graph?是。
VFX graph 粒子运算效率有多高? 简单材质下,在有场景角色的情况下,6 万左右还是很流畅的,但和粒子的大小和重叠有关,和发射的 mesh 复杂程度也相关,如果粒子 size 大,重叠多,则会严重掉帧。几轮测试后摸清了动态材质效果、音频视觉化、particle system、VFX graph,确认了其正常的表现范围。 大量反射、体积光、毛发、半透折射,这些内容确实要慎用。但就设计上来说,角色的活灵活现,体积光的替代方案,激光效果的运用,巨物大效果的视觉冲击,可大可小的灵活空间,完全忽略物理定律自然规律的数字优势,如果调整好资源的配置,已经有相当广阔的发挥空间了。
其中,最为出彩是的音画配合的流程开发部分,我们将音乐部分用 AI 工具进行了分轨处理,把人声、鼓点、电吉他等元素拆分出来,分别用不同的视效呈现其节奏及波形,在视觉上做“交响”。针对这一部分的工作流拆解,下面就说说如何“看见”声音。
VFX graph 中自带的工具 Spectrum,当把音乐赋给它,就可以把音乐转成频谱图像,从而在 VFX graph 中就可以直接调用,也就通过粒子把音频展示了出来。如视频中展现,地面黑黄相间的粒子块就是使用了 spectrum 的 VFX graph,简单实现了音频视觉化的效果;中间黑色的方块,有红色的条纹不断地闪现,就是上面所说的将音乐转成频谱图像的表现了。这种转换方式在单轴上表现出了频谱的变化,有些像是条形码,只不过是随着音频的变化而不断表现出不同的图像,这些信息在 X 轴上就足够表达出来了,在 Y 轴上没有什么变化,这也就意味着获得采样时,只考虑 X 轴就可以了。
假设有一块方方正正的舞台,且用粒子铺满了,计算这些粒子到舞台中心的距离,以这个距离采样给频谱图,基本上就得到了视频中地面的律动效果。仔细观察可以发现,地面的律动和小黑条上的频谱图像是完全对应的;小球的位置还做了进一步的处理,它代表了舞台上的演员,屏蔽了所在地面的音乐影响,避免角色与跳动的舞台之间的穿插。Spectrum 的使用方式很简单,下面介绍一下步骤。首先选取指定的音频文件,并且导入到 Unity 中;建立起一个 VFX Graph,并且添加 Audio Spectrum Binder 组件给它,如下图所示:有两种方式可以把音乐加到粒子系统中。第一种是把音乐加入到场景中,再选择刚刚给 VFX 加入的 spectrum 组件,然后把场景中的音乐拖拽上去,如下图所示:这里举例把一首名为 jay 的音乐文件加载上去。但这种方式有个问题,这个音乐并没有和 VFX Graph 一起存成预制体,在其他的场景没有办法直接引用。另外一种方式是建立一个音源节点 Audio Source 给 VFX Graph,这样就可以在资源目录里把音乐赋上去,同时可以勾选 Loop,这样音乐就会循环播放,方便效果调试,如下图所示:然后再把这个音源节点赋给 spectrum,如下图所示。这样,也完成了音乐和 VFX graph 的链接,好处是可以把这个 VFX 连带着音乐存成预制体了。在做好了外部的链接之后,就该处理 VFX 内部的调用了;VFX 中管理外部调用功能的是 Blackboard,开启 VFX 的编辑,在 Blackboard 里建立两个对外链接的节点,一个 uint 类型, 一个 Texture 2D,分别对应着 Spectrum 中的 Count Property 和 Texture Property,命名要和对应的属性保持一致,如果没有对相应的属性改名的话,应如下图所示。就会发现这个脚本里的小方块由橙色转为绿色了,黄色警告叹号的内容也消失了;完成了这些基础操作之后,可以正式开始音频视觉化的正式制作了。在这里引入一个用 VFX graph 来实践的实际案例:作为 GPU 支持的粒子,可以发射很可观的数量,放弃逐帧发射的模式,让其一次性发射 125000 个粒子:这个是计算过的这个效果需要的总数量,我们用这些粒子来摆一个立体的粒子方阵, 长宽高分别有 50 个粒子,总共就是 125000。初始数值中,粒子的生命可以设置为和音乐同等的时间,这样音乐播放结束,粒子也就清空了,我这里图简单,就直接将这一项省去了;初始的大小可以设置为 10,这样比较明显,方便后面效果的调整;这些粒子并不需要发射出去,所以初始速度模块直接删除;然后就是初始位置,做如下图的设置,通过这个 Set Position(Sequential:ThreeDimensional) 模块的设置,可以设置阵列的初始位置:制作一张类似下图的贴图,赋上去,在 Blend Mode 中选择 Additive 的模式,因为这个模式会把粒子的亮度叠得特别高,所以给予一个低亮度的颜色,就会得到如下图的效果:接下来就尝试做个动态的效果,用以确定音乐在与其挂钩的基础有效性。先计算每个粒子到中心点的距离,这样就可以得到一个渐变的球形,看我们能不能在这个结构上做出动态的变化;
如上图,求出了每个粒子到中心的距离,如果把它直接连给颜色,很难看出由于距离不同而产生的不同的变化,它会把颜色叠得特别亮;粒子的数量比较多,这也使得很难看到内部的粒子表现;然后还要考虑到让它动起来,才能确定效果的基础,所以做了如下图的运算:
1. 首先乘以 0.03,这是一个试出来的数值,可以使得距离上的变化区间比较合适;
2. 加上时间,可以让这个数值不断的变大,产生变化;
3. Fractional 进行了求余的运算,使不断变大的数值变循环往复起来;
4. 先乘再减,可以让数值的区间更加接近我们想要的,明暗明显,变化节奏鲜明;
5. clamp 使得数值在正常的表现区间,不会出现负值,也约束了最大的亮度;
6. 最后的这个乘以 4,就是根据效果,最后调整一下亮度;
我们把这一系列的运算连给 color,让它实时更新亮度变化,最后在渲染中再乘以一个紫色,就得到了一个节奏明显的动态效果。
这样就得到动态的结果了,下一步就是要呈现出音乐影响的效果。如图以距离作为“U”,忽略掉 V,对音频进行了计算,同时设定了振幅并将这个参数暴露出去调整,如同上面那个 0.03,这个振幅也需要一个很小的数值才能有个不错的效果;关于颜色,可以自行设计算法来使其表现出自己想要的变化。
把这个音乐球放在舞台上就呈现出了如下面视频中的效果:这里就是将一个平面上的粒子,以方形 mesh 为粒子形状,音乐采样到中心距离的情况下, 影响粒子的高度变化。这个又降低了一个维度,对一条线上的粒子做音频影响,可以同时影响位置、高度、颜色等等,中间高两端低的呈现方式并不是把音频引入直接获得的,而是做了 lerp 差值算法得到的,算法不唯一,自由发挥。
关于 Spectrum 的扩展,上面所使用的音频视觉化,均是以 VFX graph 为载体呈现的。但万事万物皆可与音乐一起律动,那么官方提供的 spectrum 就需要扩展到其他的效果应用上,你需要个加强版的 spectrum。 这里你可能需要 TA 或是程序的支持,Unity 中有一个 API :GetSpectrumData,可以用于获取音乐的频谱数据,然后对这些数据进行处理以创建频率带,使用 CreateFreqBands8() 函数用于创建 8 个频率带。它计算每个频率带的平均值,并根据音频频谱数据分配给每个频率带的强度,最后将结果乘以指定的频谱功率。在对应的模型挂上脚本后,需要使用固定 Properties 名称以确保参数传入 shader,强度对应的名称是 _SpectrumOutputDB,创建以 _SpectrumOutputDB 命名的 float 变量后,我们就把参数导入shader了。
但是在这之前还需要处理一下数据,由于音频文件高低值跨度过大,所以会导致这个参数会有大于 1 小于 0 的情况出现,这个在 shader 中控制明度值时,小于 0 或者大于 1 会出现出错,所以我们还需要用 remap 重新映射参数范围。这样,材质上音乐表现就可以创造了。
说到了音乐的频谱,直接使用起来会发现还是相当不好用的,因为我们能听见的声音大部分都发生在频谱的左侧,对于整体而言,大都是“低频”,这也意味着可以通过调整 spectrum 的算法来进行优化,从而免去了大幅调整粒子系统内部或是 Shader 内部算法的工作。
VFX graph 呈现了数量化,阵列化的特点,那么也安排了其他的效果打配合。
这个舞台背后巨大的屏幕,就是由多层多个复杂的材质构成的,在音乐的高潮阶段呈现出来;视频中看到的是所有层叠加在一起时展现出来的效果,在实际的 show 中并不是这样出现的。分了很多个层的原因是方便随着音乐的变化调整动态表现不同的节奏。这种复杂的效果,体现了材质的表现优势。
场景中也应用了很多 Unity 中特效制作使用最多的传统的 particle system,下面角色手上不断散发的有点像水粒子的就是。
这里并没有试 VFX graph,虽然 VFX graph 也可以轻松做到。VFX graph 是基于 GPU 计算的粒子,在整场表演里,我们已经使用了太多的 GPU 了,为了不再增加 GPU 负担,就选择了 particle system。
可以注意到的是,角色身上也有发光的材质,还和音乐进行了联动,加上手上的粒子,是我们强调角色的手段。下面几张截图,可以看出强调角色的必要性:
综合使用特效,可以更好调配性能效果比,表达的内容也更丰富有层次;在这里我们摈弃了过去所擅长的镜头语言控制,去除了破坏沉浸感导致眩晕不适的这种可能性。由于体验者有可能看向任何一个方向,只有通过全景、全方位的配置资源,不断测试、体验、替代方案、再测试……才是这个环节最大的工作量。
在性能允许的情况下触碰效果的天花板,是预研发想要达到的目标,因此有很多资源被各种原因替换了下来,例如上面那个球形效果的 spectrum 案例就因为消耗过大而下场。Timeline,即这次使用的核心工具。这一工具拥有相对简单的结构和易于掌握的特性,对开发者比较友好,但在之前并没有于 Vision Pro 平台使用它的经验。这里需要注意,开始小组使用的 VFX graph 12 版本并不支持 Timeline 中的 control track,调整动画时粒子系统的时间线和 Timeline 的无法保持一致,导致前期工作效率提升不上来,随后 update 到 14 的版本,这一问题得到了解决。如果你们面临类似的需求,也请注意这一点。
以及一些展望,如果在后续的开发路图中能够支持多人协作,对于这样的项目类型也会有很大的帮助。
VFX graph,即本篇重点阐述的模块。很开心在这次尝试中使用到 VFX graph,这是一个有着相当自由度的粒子系统,Shader Editor、Houdini、Blender 等软件及中间件在节点编辑的基础上能够最大限度为设计师提供自由创作的空间。这种自由度既体现在了算法上,同时也带来了复杂度,如 Shader Editor 给特效工作者提出要求的同时,也赋予了 TA 工作者效率控制的目标。从这个角度来讲,使用 VFX graph 的项目做到有效的工具化与规范化,会在最大程度上减少优化所带来的工作阻力。
音乐,即这场秀的基石。在选定音乐时,选中的这一首也许不是备选曲库中最好听的,但它有着清晰的段落感,并且逐级递进的优点,评估时想到如果可以实现画面上的段落配合,将会给体验提升一个层次。但由于一个月的时间节点,我们没有将这点做好,留下不少遗憾,希望能在未来的开发中补足。另外音乐本体也没有进行更细致的处理,这部分还是有不少可以预见到的深化内容,随着硬件的提升、更细致的音轨拆分、效果配合、环境音源在场景中的动态配置,相信会带来更立体的听觉体验,同时也呈现出了音频领域技术栈积累的客观需要。
篇幅仓促,本篇重点介绍了本次 Unity 环境下 Vision Pro 踩坑开发的 VFX 部分,之后会进一步展开 Timeline 和动力学的相关模块。预研成功后的产品化进程中,相信这些模块也会随着引擎版本优化而变得更易于使用,届时欢迎开发者朋友联系我们体验与交流,探索空间计算中不同模式下新的交互和表现的可行性。| 本文作者:云峰、阿火
Unity 中文社区持续征集内容投稿,欢迎与 Unity 官方分享你的技术笔记、项目 demo、行业经验、有趣案例,加入社区建设,繁荣内容生态,带领百万 Unity 中文开发者一同学习。方式一:在 Unity 中文社区首页(https://developer.unity.cn/)创建个人账号,发表文章;方式二:在 Unity 官方开发者服务平台微信服务号点击【联系我们】-加入社区建设-技术内容投稿。