版本
听者是代表游戏中麦克风位置的游戏对象。将一个游戏对象指定为听者可以让 3D 声音被指派到扬声器,以便模拟真实的 3D 环境。与之相似,发声体游戏对象代表一个虚拟扬声器,当它被指派到一个听者时,发声体的位置信息就被映射到听者的坐标系统中,以此渲染出 3D 声音。Wwise 中会给所有的游戏对象指派一个变换(transform)——一个位置向量以及前方和上方向量,不管这些对象是作为发声体还是听者(或两者都是)。游戏对象的变换必须每帧更新,保证声音通过正确的扬声器进行渲染。
为了听到声音,至少要注册一个游戏对象并且将其指派为听者。您可以使用 AK::SoundEngine::SetDefaultListeners
来将听者指派到所有其它游戏对象,或者用 AK::SoundEngine::SetListeners
来将听者指派到特定游戏对象,并覆盖使用 AK::SoundEngine::SetDefaultListeners
所做的设置。以下是我们注册游戏对象并将其指派为默认听者的方法:
AkGameObjectID MY_DEFAULT_LISTENER = 0; // 注册主要听者。 AK::SoundEngine::RegisterGameObj(MY_DEFAULT_LISTENER, "My Default Listener"); // 将一个听者设置为默认。 AK::SoundEngine::SetDefaultListeners(&MY_DEFAULT_LISTENER, 1); // 注册游戏对象来播放声音 AkGameObjectID MY_EMITTER = 1; AK::SoundEngine::RegisterGameObj(MY_EMITTER, "My Emitter"); // 这时“My Emitter”有一个听者,即“My Default Listener”,因为我们已将其指派为默认听者。 AkGameObjectID MY_LISTENER_NO2 = 2; AK::SoundEngine::RegisterGameObj(MY_LISTENER_NO2, "My Listener #2"); // 如果我们只想为“My Emitter”变更听者,可以按以下方式: AK::SoundEngine::SetListeners(MY_EMITTER , &MY_LISTENER_NO2, 1); // 这时,“My Emitter”有一个听者叫作“My Listener #2”。所有其它游戏对象仍然有“My Default Listener”作为它们的听者。
您可以通过在 Wwise 设计工具中查看 Advanced Profiler 的 Emitter-Listener 选项卡,来检查已在代码中指派的发声体-听者关联。简单的游戏会选择一个游戏对象作为所有游戏对象的默认听者;但是也可以使用多个听者输出到一个输出设备上。请见以下的 单一输出设备中的多个听者 。我们也可以将听者用于子混音的 3D 定位。想要做到这点,需要将听者指派到特定的游戏对象,这些游戏对象同时也是听者,它们创建出游戏对象和听者相互关联形成的有向图。
就像针对所有游戏对象一样,要使用 AK::SoundEngine::SetPosition()
函数来设置听者的位置。只要 Listener 的任何位置或朝向向量发生变化,就应执行此操作。
AkTransform listenerTransform; (... 在此设置 listenerTransform 的位置和朝向成员……) AK::SoundEngine::SetPosition( listenerPosition );
AkTransform 类型保存着在游戏 3D 空间中定义听者位置和指向的信息。听者的位置(Position),OrientationFront,以及 OrientationTop 向量可以使用 AkTransform
类型的 getter 和 setter 来访问。
|
Note: OrientationFront 向量定义 Listener 头部的朝向。此向量应该与 OrientationTop 向量正交,后者用于定义 Listener 头的斜度。对于人类听者,可以将 OrientationFront 向量视为听者的鼻子(伸出面部指向远处),而 OrientationTop 向量与它正交,从鼻子指向上方,位于听者眼睛之间,经过额头继续向上。 |
请参阅 X-Y-Z 坐标系统 了解 Wwise 声音引擎中 X、Y 和 Z 轴分别对应什么。
必须定义朝向向量,才能正确渲染音频。它们不可以是零向量,需要是单位向量。它们也必须是直角。
|
Note: Listener 的信息最多每帧更新一次。即使多次调用了 AK::SoundEngine::SetPosition() 函数,调用 AK::SoundEngine::RenderAudio() 时只考虑最后一个值。 |
|
Tip: 如果您遇到声音渲染上的异常情况,例如原希望从左扬声器中发出的声音结果却从右扬声器中发出,则应通过 AK::SoundEngine::SetPosition() 函数检查提供给声音引擎的 Listener 位置信息。您可以尝试设置一个已知的 Listener 恒定位置,检查在此情况下渲染是否正确,以排除混淆了 X、Y 和 Z 轴的情况。有关此功能的详情,请参阅 X-Y-Z 坐标系统 。 |
在单人游戏中,您始终只有一个视角,因此一个 Listener 就够了。然而,如果多个玩家可以同时在同一系统上玩游戏,或者同时显示多个视角,那么各个视角都需要有自己的 Listener ,从而正确地为所有这些视角渲染音频。
实现多个 Listener 的主要难点在于声源的定位对于玩家所见并不总是合理。这主要是游戏仅使用一组扬声器来为多个玩家再现 3D 环境所造成的。
下图简要地展示了这一问题。由于 Listener 0 希望在左扬声器中听到声源,而 Listener 1 希望在右扬声器中听到声源,因此很难讲哪些扬声器应该用来播放声源。
图:两个 Listener 在不同的扬声器中听到相同的声源
Wwise 中可以有任意数目的听者,默认情况下所有听者会在主输出设备中合并,除非:
AK::SoundEngine::SetListeners
向另一个听者发声的,或AK::SoundEngine::AddSecondaryDevice
连通到一个辅助设备。以下的部分包括了当所有听者融合到同一个输出设备时的例子,也描述了 Wwise 声音引擎如何让程序员操作这些听者,以便完成期望的行为。
|
Note: 多 Listener 功能影响 3D 游戏定义模式中设置的声音对象。我们不关心定位设置为 2D 模式 或 3D User-defined(3D 用户定义模式)的对象,因为这些模式下设置的对象独立于游戏环境中的声源位置和 Listener 位置而定位于各个扬声器中。 |
|
Note: 与多个 Listener 相关的一切功能都只能由游戏程序员通过 SDK 来实现。Wwise 设计工具中没有专门的选项用来为多个 Listener 管理声源在游戏中的定位。 |
每个听者都会生成一个混音图。对于各个声源,相对于它们所作用的各个 Listener 分别计算距离衰减和声锥衰减。
当多个听者在捕获一个声源时,声源会在它相应听者对应的每条总线实例中连续混音。在混音时,每个听者会独立应用衰减音量。
与衰减音量相反,衰减 LPF 和 HPF 会直接在声源上应用;因此,Wwise 必须基于特定声源的所有发声体-听者关联选择一个值。以下是声音引擎如何计算要应用于各个声源的最终低通滤波器:
在下表中详述的示例中, Listener 0 的值是 max( 10, 40 ) = 40, Listener 1 的值是 max( 50, 10 ) = 50。两值中的最小数是 40,然后将此数与对象的值 5 相加,从而获得最终值 45:
|
|
|
the source |
||
|
|
|
|
||
10 | 40 | 50 | 10 | 5 | 45 |
空间化是指根据3D Game-Defined(3D 游戏定义的)声音相对于 Listener 的位置,在各种扬声器之间对这些声音的定位。
然而,如果两个玩家在分屏显示器上玩游戏,您可能会希望在左扬声器中听到听者 1(第一个玩家),在右扬声器中听到听者 2(第二个玩家),而完全不用根据声音相对于各个 Listener 的位置在扬声器之间定位声音的常规办法。
为了提供更多的控制和更高的灵活性,Wwise 可以让游戏程序员对指定的 Listener 禁用空间定位,也可为各个声道设置自定义音量偏置,从而指定在各个扬声器中将如何听到此 Listener 捕获的声音。
可以调用 AK::SoundEngine::SetListenerSpatialization()
来修改各个 Listener 的这些设置:
virtual AKRESULT AK::SoundEngine::SetListenerSpatialization( AkGameObjectID in_uListenerID, // Listener game object ID bool in_bSpatialized, // Spatialization toggle (True : enable spatialization, False : disable spatialization) AkChannelConfig in_channelConfig, // Channel configuration associated with volumes in_pVolumeOffsets. 如果 in_pVolumeOffsets 为空,则忽略。 AK::SpeakerVolumes::VectorPtr in_pVolumeOffsets = NULL // 各个扬声器的音量偏置,单位:dB。请参见 AkSpeakerVolumes.h 了解如何操作此向量。 ) = 0;
第一个参数是 Listener ID。第二个参数必须设置为True
,以针对此 Listener 启用空间定位,或者设置为False
,以禁用它。最后两个参数代表包含该 Listener 上各个声道的衰减的向量,单位:dB。如果 in_bSpatialized
是 False
,则它为各个声道设置音量,在默认情况下音量是 0dB。如果 in_bSpatialized
是 True
,它会针对各个声道将默认 3D 游戏定义的定位运算获得的音量值按给定量做偏置。
音量向量绑定到声道配置 in_channelConfig
。如果 in_channelConfig
为 5.1,则音量向量应有 6 个值。使用 AK::SpeakerVolumes::Vector namespace 中定义的功能操作它。声道顺序对应于 AkSpeakerConfig.h 中定义的声道掩码位(channel mask bits),LFE 除外(总是位于末尾的)。
对于两个玩家使用分屏玩游戏的例子,程序员可使用以下代码:
// 将听者 1 和 2 注册为所有发声体的默认听者。 // 您也可能最好通过换用 AK::SoundEngine::SetListeners 来明确选择哪些发声体向哪些听者发声。 AkGameObjectID listeners[2] = {1,2}; AK::SoundEngine::RegisterGameObj(listeners[0]); AK::SoundEngine::RegisterGameObj(listeners[1]); AK::SetDefaultListeners(listeners[0],2); // 使用 7.1 扬声器设置定义扬声器偏置(如果平台支持的话) AkChannelConfig cfg; cfg.SetStandard( AK_SPEAKER_SETUP_7_1 ); AkUInt32 uVectorSize = AK::SpeakerVolumes::Vector::GetRequiredSize( cfg.uNumChannels ); AK::SpeakerVolumes::VectorPtr vVolumes = (AK::SpeakerVolumes::VectorPtr)AkAlloca( uVectorSize ); vVolumes[0] = 0.f; // 左 vVolumes[1] = -96.3f; // 右 vVolumes[2] = -6.f; // 中置 vVolumes[3] = 0.f; // 左后 vVolumes[4] = -96.3f; // 右后 vVolumes[5] = 0.f; // 侧左 vVolumes[6] = -96.3f; // 侧右 vVolumes[7] = 0.f; // LFE AK::SoundEngine::SetListenerSpatialization( listeners[0], false, cfg, vVolumes ); vVolumes[0] = -96.3f; //左 vVolumes[1] = 0.f; // 右 vVolumes[2] = -6.f; // 中置 vVolumes[3] = -96.3f; // Rear left vVolumes[4] = 0.f; // 右后 vVolumes[5] = -96.3f; // Side left vVolumes[6] = 0.f; // 侧右 vVolumes[7] = 0.f; // LFE AK::SoundEngine::SetListenerSpatialization( listeners[1], false, cfg, vVolumes );
如果声音通往的总线按照用户定义的声道配置而不同于 7.1,则声道向量将使用标准的下混配方在内部下混,然后再作用于声音。
要改回使用常规的空间化,您可以调用:
// Enable regular spatialization on listeners 0 and 0 AK::SoundEngine::SetListenerSpatialization( 1, true ); AK::SoundEngine::SetListenerSpatialization( 1, true );
下图按照执行的顺序展示对各个声源所做的不同操作,以使各个 Listener 能够计算各个扬声器中的最终音量:
图:Wwise 声音引擎中的音量管线