让VR沉浸感再进一步 Unity工程师孙志鹏分享VR空间音频技术
为了打造沉浸感,除了视觉、交互设计外,音频同样是非常重要的一环。事实上,很多知名VR游戏和影视内容团队在分享中都会强调VR空间音频对于作品的重要性。但如何利用好VR空间音频,大家都处在不断摸索和尝试的过程中。在前不久的Unite 2017 Shanghai大会上,来自Unity的工程师孙志鹏分享了对于VR环境中音频构建的思考和建议。
此外,孙志鹏还表明:360视频没有镜头的概念,是空间化音效的一个非常好的使用场景。他随后比较了空间化音效技术在不同平台和设备上的性能消耗,并表示这是一项具有可行性的技术。
以下是Unite‘17上演讲内容:
大家好!我是来自Unity的现场工程支持师,我叫孙志鹏,今天我们分享的主题是在VR环境当中的音效。很高兴今天能够在这里和大家分享这个话题,声音作为一个一直不太受开发者重视的元素,我们一直都在讨论画面之类的东西,但在VR中创建沉浸式体验,声音也是非常重要的一环。玩家和观众在虚拟的环境当中听到一个声音来自于虚拟世界当中的位置,会变的非常重要,原因就是我们在沉浸式体验当中没有了屏幕的概念。如果说是叙事的环节的话,也没有了镜头的概念,我们要推动故事情节的发展需要引导玩家,声音是非常优雅而简便的,也是实用的选择。
音效如何变的空间化呢?首先要了解人类是如何定位空间中的声音的。这个过程可以简单地分为两个方面,人类是如何定位声音从哪个方向过来,离我们有多远。定位方向无非要知道声音是来自于前后左右还有多少角的方向。最主要的就是靠时间差ITD和强度差来判断左右,这两个参数的判定优先级是跟人头的尺寸有关的。这里有一对经验值,800赫兹以下的是靠时间差来判断的,高于800赫兹是靠强度差,中间是靠他它们两个之间的是共同判定的。
有时候在实际生活当中也会用侧耳倾听的方式把判断前后的问题改为判断左右的问题,值得一提的是人类对于前方的声音的精确度可以做到1度,对于侧边的声音也可以做到15,人的听觉系统可以分辨10毫秒以内的时间差,所以我们要在开发过程中能够达到相应的精度才能让体验者不会感到声音是虚假的。
那我们来看看ITD(时间差)和ILD(强度差)是的影响权重是如何和人的头的尺寸相关的,之前我们提到过800Hz以下我们就只能看时间差来分辨声音的左右了,以图中200Hz的声音为例声音的半波长大约是85cm远大于我们的头的尺寸所以在这个情况下我们根本无法挡住声音,所以声音的强度差显然靠不住了,而在高于1500Hz的6000Hz声音的情况下,我们会完全的挡住声音,所以我们无法靠时间差来只能依赖于强度差,而对于前/后和仰角就让我们交给hrtf吧。
接下来让我们来看看人类是如果定位空间中声音的距离的。对于熟悉的声音,及我们知道何为大声和为小声的声音,当然是声音越大离我们越近,对于表示直接声音和经过一次反射的声音到达耳朵的延迟的Initial Time Delay来说,延迟当然是越大,说明声音里我们越近,对于我们听到直接声音和反射声音的比例来说,当然是直接声音的比例约高,说明音源离我们越近。对于听觉的运动视差来说,越近的声音运动的会越快,想象我们站在铁路边一辆火车以恒定的速度从远处开来。我们听到火车的声音由远及近时一开始声音移动的很慢可到了近处后,火车呼啸而过,声音移动的很快。高频声音在传播的过程中会比低频声音衰减的更快。所以高频部分衰减的越少说明约近。
对于7.5和5.1的环绕立体声来说,依靠听者的位置和朝向的假设。这种情况下在家庭影院上是可以的,我们可以假设定者的地位和朝向的位置。
我们知道人类是如何定位3D空间中的声源,3D音源的空间化就是逆向的过程。简单来说就是我们处理我们的声音,让它听起来像是发生在空间当中的那个位置。这样做自然要从两方面来处理,一方面是总方向上,另一方面是从距离上。方向上主要是可以靠HRTF加上头部跟踪里处理,具体就是利用刚才讨论的那些关于声音距离方面的特征属性来逐一地处理。
首先我们要明白什么是HRTF,但是在说明之间不得不先解释一下什么是HRIR,头部关联的脉冲响应。HRIR是一个与音源和耳朵位置相关的脉冲响应,对任意音源做某一特定HRIR的卷积就是把该声音处理成像这个脉冲响应关联的耳朵和声音的位置,音源在这个HRIR相关联位置发出声音的过程。我们现在已经知道什么是HRIR了,它可以把我们的声音处理成像那个位置发出的声音,在这个过程中可以做卷积。傅立叶变换可以把卷积变成乘法,乘法变成卷积,这里我们显然希望使用乘法来代替卷积运算从而减小性能的开销。所以我们需要HRTF。
那么我们在来给HRTF一个更近一步的解释。HRTF是因为散射导致的基于音源位置的选择性的加强和衰减某些特定频率的现象。耳朵在这个过程中扮演了一个声音探针的角色。这个效果可以在数十分贝的数量级上影响某些特定频率声音的大小。这个图可以让我们对HRTF有一个更直观的认识,它横轴是频率,大概能到40000赫兹的范围,纵轴的加强的分贝数。它对于一个特定的角度、特定的距离对于特定频率的声音加强和衰减,这个图是前方仰角15度的一个HRTF。绿色的线是左耳,蓝色的线是右耳。
值得一提的是几乎每个人的HRTF都因为不同的头部大小和不尽相同的身材,独特的耳部特征,所以每个人的头部模型都是一个独一无二的个人属性。
HRTF是怎么来的,是在一个完全不会发生反射的房间用这样的一套设备来测量的。我这里列出来wiki上能搜到的一些数据,让我们的开发者可以不用自己去模拟HRTF开发方式,可以直接做声音的处理软件。
这张图上可以大致地想象出来,这个数据是什么样的,它应该是以听着为中心的球面数据,我们是靠声音在空间中的两角和方位角去索引我们对的HRTF,就像我们上一张看的图一样正前方15度是有一个专门的图。
现在让我们来看看HRTF是怎么使用的。假设空间中的一个特定位置的扩音器发出的声音为X1,X1经过扩音器的transfer function传播到听者所在的位置,这个时候要经过有人体特征构成的天然滤波器,就是HRTF到鼓膜被我们听到。假设这个时候在鼓膜处有一个话筒,可以把我们听到的声音给记下来,记录下来为Y1.那么当我们想在耳机里直接模拟出这个过程时,我们就需要有一个transferfunction涵盖LF/H的整个过程,是的最后同样在鼓膜里听到的Y2和之前的Y1完全一样。
头显在这当中扮演了什么角色呢?在L和F的过程当中,头显追踪到头部,声源在虚拟场景的更新都要应用到相应的LF工具里面去,这个时候我们才能做声音的处理。
说完了方向之后看一看刚才说的距离,距离就比较好处理了,每一条都有符合认知的的感觉。声音从远到近,会因为距离而衰减。直接声音和初次反射声音的时间差,从远到近,会由小到大。直接声音和反射声音的比例,从远到近,直接的声音的比例也会逐渐增高。声音的移动上来说,正如之前讲到火车的例子,从远到近,音源的移动速度也会由慢到快。这在虚拟现实中是非常好的获得的一点,虚拟场景本身自己对声源的控制我们天生得到这样子的优势,我们把声源绑在虚拟的场景当中的物体上,天然得到了这样子的优势。高频声音的衰减来说,我们需要在考虑声音基于距离衰减的基础上,让高频的声音衰减的更快。
我们现在已经了解了如何在耳机里模拟一个空间中特定位置的声音。那么下面让我们的看看这个过程如何在unity里快速的实现。Unity为我们的开发者提供了一个空间化音效的SDK,要讨论这个SDK我们不得不提到Unity里的Native Audio Plugin SDK,因为它是我们空间化音效SDK的基础。
Unity里让开发者创建Audio effect,任何一个Audio Effect都可以用这个SDK完成,它可以像一个graph一样去构建复杂的音效。
像图中的例子,我们想把两个音源的做一个混合的效果。我们可以创建音效,指明它在音源里面有输出,在callback函数里面最关键的就是process call back这个函数,让我们的开发者可以在这里对音源的每一个channel的每一个sample做处理。
好,在Native Audio Plugin SDK的基础上让我们来认识一下空间化音效的SDK,以及如何在这个SDK的框架下实现我们的空间化音效。
相对Native Audio Plugin SDK,Spatialization AudioSDK唯一的不同是在整个声音特效的graph里,在这里设计空间化音效,对场景当中每一个功能的音效都会创建唯一的音效instance在graph里与之相连。这个时候只要空间化音效打开,不管你场景稻种的Audio Graph多么复杂,它都会在里面加入唯一过滤的声音。
好,接下来让我进入具体的实现环节。首先是Capturing HRTF,当然我们也可以选择不用自己Capture,而使用一些现成的数据。
在unity提供的sample里,我们使用的是MIT EDU提供的数据,它的数据结构是这样的,有14个仰角,对于每一个仰角有一定数量的方位角,比如说对水平向下40度的角度,提供了16个Sample点,每个点之间的差是4.63,这样的一组数据是以人为圆心的不封闭的圆,因为是从我们头顶90度一直到水平向前40度就结束的一组数据,刚才采集HRTF的半径是1.4M。
然后我们来讨论一下在SDK里Apply HRTF的过程。在刚才讨论最主要的ProcessCallback里,根据方位角和仰角,我们找到对应的HRTF,处理我们音源里的sample data,它的信号是一个时域空间的信号,声音是跟时间有关的数据,我们在时域空间需要对它进行做卷积,卷积的运算量是非常大的。对于这种数据我们就要用这里提供的Unity Audio SDK的傅立叶变换,将离散空间的数字化锦灏转化到频域空间,这样我们就可以用复数乘法代替卷积运算。这样可以减少性能的开销。在处理完对特定频率的增强和衰减以后。我们再把audio data的转回时域空间,写入这个audio effect的output buffer,这样的节点可以传给下面的节点去做操作。
但是在这个过程中的计算量仍然是比较大的,且像这样的没有太多逻辑关系的纯计算任务也比较适合在GPU上完成。所以现在的一些GPU厂商也相继为这样的需求提供GPU的硬件加速支持。比如AMD提供的TrueAudioNextSDK,它提供了一套与Unity Audio SDK里很相似的API来做傅立叶变换和复数乘法,甚至也有卷积运算的函数。其实它API的使用方式和Unity里面的API使用方式非常相似,但是它的内部是用GPU加速的,所以这样可以让我们在声音计算的过程中也享受到GPU带来的运算性能。
然后在Head Tracking的部分我们需要将头显的方位数据apply到场景当中带有audio listener这个组件的camera上,使得我们在process call back 里拿到的listener matrix才会变成头显的位置。对于Unity支持SDK的硬件这个过程是自动完成的,但如果有一些不在这个范围的厂商头显,要去适配需要自己去做这个过程,或者我们需要做一个跟它类似的SDK在Unity里面去适配其他的头显,对于这两款头显Unity里面已经做了适配,它关联的过程自动的。
接下来来看一下在方向的空间化,再来看看距离的方面。对于声音的衰减和声源的移动来说,我们可以在CreateCallback里注册一个距离相关的衰减回调,然后在这个回调函数里我们可以得到当前声音和听者的距离,我们可以增加一个距离声音的衰减并把它应用到音源数据上。
对于Initial Time Delay 和 Direct/ Reflectionratio这两个方面,牵涉到声音在三维场景中的反射。即牵涉到了复杂的三维场景,计算量变的非常复杂。我是用一个近似的方法来模拟复杂的3D场景。使用一个cube来模拟3D场景,让我们有反射的感觉。
所以我们可以在Create Callback里创建注册一些描述这个近似模拟场景的cude的属性长宽高,然后Unity可以自动生成相应的UI,让我们的audio effect使用者来做调整参数。然后我们在process call back里可以根据这些数据来计算反射,避免引入复杂的三维场景当中声音的反射。
对于高频的衰减来说,我们可以在之前HRTF的处理过程中,在转化到频率空间之后,我们是有一个机会去看高频的声音在哪里,我们有机会去定义什么是高频的,在Callback函数里面我们也可以拿到一些值,所以我们可以在这里做一个频率相关的距离衰减。
我这里有一个简单的Demo,是关于360视频。因为360视频里没有了镜头的概念,所以当用360视频来叙述故事时,让观众看向剧情发展的地方变的非常重要,这也是空间化音效的一个非常好的使用场景。我们可以靠声音引导观众看重哪些地方。我是下载了360视频放在Unity里面,为了大家看的方便,在每一个声音在的位置都有一个球,这个场景地方一共有300个空间化的音效。
在Mac的笔记本上如果是20帧的消耗,跑到120帧的画面场景中20个HRTF音源性能消耗大约时3%左右。同样的360视频,同样的mac笔记本,300个HRTF音源性能消耗大概到27%,但是这时候还有很长的时间发在WaitForTargetFPS,因为我把帧数定在120,如果我们增加到600个HRTF,苹果笔记们也是可以接受的。
这个技术在andriod设备上的表现同样的360视频,300个HRTF音源,在小米四上大概有20几帧,至少可以证明它是可以使用的技术,在移动设备上用它有几百个也是可以跑的起来的。
我的分享就结束了,谢谢大家!