目录

Wwise SDK 2018.1.11
集成 Wwise Motion

Motion 功能方便用户控制控制接口的触觉反馈。通过 Wwise,您可以使用您用于管理应用音频的相同功能集来管理 Motion(振动)。从内部来说,振动数据与音频数据并无差别。也就是说,所有适用于音频的功能同样适用于振动。Wwise 振动功能能够实现两种类型的触觉反馈。您可以在工程中使用音频信号并将其转换为振动,也可以使用 Motion Generator 源生成专用振动信号。只要配有支持的控制器,就可在 Windows 上直接使用 Wwise 设计工具来测试此功能。

振动组件

Motion 利用 Wwise 声音引擎插件系统在应用程序中实现自身功能,并可划分为两个模块:音频源 (Motion Generator) 和音频设备 (Wwise Motion)。Motion Generator 是一款强大的可选工具,方便精确而灵活地设计振动。

Motion Sink 插件

Motion Sink 插件可被视为声音引擎和振动设备之间的连接纽带。正如其他 Sink 插件一样,它从一组听者接收数据,并负责将数据呈现给设备。此插件设在单独的库内,并需要同时包含在设计工具和应用程序中。请参阅 设置振动 一节了解更多信息。

Motion Generator 源插件

利用 Motion Generator 源插件,您可以精确地设计触觉反馈效果器的行为。正如其他音频源一样,您可以将 Motion Generator 添加至 Wwise 工程中的 Sound SFX 节点,从而生成基于曲线的触觉反馈。请确保将 Sound SFX 节点的 Output Bus 设为振动总线。

设置振动

为了在应用程序中使用振动功能,必须正确设置各个组件。注意,所有适用于音频流程的概念同样适用于振动。它使用相同的总线、听者和发声体(参阅“ 集成 Listener ”)。

Wwise 设计工具设置

为了能向设备发送声音或振动数据,必须将经授权的 Wwise Motion ShareSet 添加至 Wwise 工程的 Audio Device 文件夹。Audio Device 文件夹位于 Project Explorer 的 ShareSets 选项卡中。Wwise Motion ShareSet 是声音引擎用来与振动设备进行交互的 Audio Device 插件。同时,必须将 Wwise Motion ShareSet 指派给顶层 Audio Bus。为简单起见,“振动总线”统称指派有 Wwise Motion ShareSet 的顶层 Audio Bus。为了方便排除故障和监控,最好在工程中使用单个振动总线层级结构。现在,您可以将任何 Sound SFX 的 Output Bus 设为振动总线,以便创建触觉反馈。通常,使用振动总线的 Sound SFX 元素会同时使用 Motion Generator 源。为了模拟音频和振动,Sound SFX 须至少拥有一条振动总线和一条音频总线(作为 Output Bus 或 Auxiliary Bus)。

游戏设置

在游戏端,首先须确保链接 AkMotionSink 库。此库为所支持平台的标准控制器提供支持。同时,还需包含 SDK\include\AK\plugin 下的 AkMotionSinkFactory.h 文件。此文件用于自动注册插件,因此必须包含在内。

Note: 在 Unity 中,会自动管理插件库。无需手动添加 AkMotionSink。

有关支持的控制器及其他要求,请参阅下表。

平台 设备 其他要求
Android 支持振动效果的 Android 设备
iOS 不支持。由于 Apple 的规格限制,iOS 设备上的触觉反馈 API 无法满足 Audiokinetic 对 Motion 功能的支持要求。
Linux 不支持。
Mac 不支持。
PlayStation 4 DUALSHOCK 4
PlayStation Move
Switch Joy-Con
Windows Xbox One 控制器
Xbox 360 控制器
DirectInput 控制器
XInput.lib
Dinput8.lib
Winmm.lib
Xbox One Xbox One 控制器

如果应用程序要在一些设备上使用振动,则要为每台设备添加专用输出。比如,对于连有四个玩家的分屏游戏,需要添加四个不同的输出以便各个控制器分别接收触觉反馈。若要添加输出设备,请使用 Wwise API 函数 AK::SoundEngine::AddOutput,并在 AkOutputSettings 参数中指定 ShareSet 名称(如 Wwise 工程中所定义)。. 另外,因为可能连接多个设备,所以还必须提供设备 ID。有关设备 ID 的详细信息,请参阅下表。为了在使用单个控制器时简化设置过程,将支持使用默认设备 ID。在使用 0 值时,Motion Sink 将指向第一个支持振动效果的相连设备。

平台 设备 信息
Android 支持振动效果的 Android 设备 使用 0 值。
iOS 不支持。 -
Linux 不支持。 -
Mac 不支持。 -
Windows XboxOne 控制器
Xbox360 控制器
使用玩家索引 (0 ~ 3)。
Windows DirectInput 控制器 使用 DIDEVICEINSTANCE 中存储的 guidProduct。使用 AK::FNVHash32 生成 guidProduct 哈希值。
PlayStation 4 DUALSHOCK 4 使用 scePadOpen 或 scePadGetHandle 返回的设备句柄。
PlayStation 4 PlayStation Move 使用 scePadOpen 或 scePadGetHandle 返回的设备句柄。
XboxOne XboxOne Controllers 使用 IGamepad 对象中存储的 ID。
Switch Joy-Con 结合使用 nn::hid::NpadId 和规定索引

注意,游戏控制器可能因连接问题或通信问题而断开。除了浪费一些资源外,它不会对声音引擎产生任何不利影响。若认为设备已经断开很长一段时间,则须调用 AK::SoundEngine::RemoveOutput,并提供调用 AddOutput() 函数时调用返回的 AkOutputDeviceID。这样可以释放资源。

多人游戏考量因素

振动输出跟其他 Secondary Output 是一样的,因此也存在相同的限制和要求。假如您在制作单人游戏(即只有一个玩家在本地控制游戏),Listener/Game Object 设置会非常简单。一般情况下,新的振动输出将把同一默认 Listener 复用为主音频输出。也就是说,在单人设置中基本上不需要管理 Listener。 

假如您在制作多人游戏,则需要为每个振动输出创建一个 Listener/Game Object。只有如此,各个玩家才能分别获得游戏情境产生的对应触觉反馈。在 \c AK::SoundEngine::AddOutput() 初始化输出的同时,必须初始化与设备关联的 Listener。各个 Listener 会为声音或振动提供附加通路层。在针对只与某个玩家的 Listener 关联的 Game Object 上播放 Event 时,可让声音只被该玩家听到。这一关联可通过调用 \c AK::SoundEngine::SetListeners 来完成。请参阅 \ref soundengine_listeners 了解有关Listeners和Game Objects的更多信息。注意,您也可以将多个 Listener 与同一 Game Object 关联,生成作用于所有 Listener 的“广播”效果。

<table border="0" cellspacing="0" cellpadding="2"><tr><td valign="top"><img src="images/Note.gif"></td><td><b>Note:</b> 即便 Emitter 作为 Listener 采用振动输出,也要将对应的声音连入振动总线层级结构。</td></tr></table>

示例

以下示例将展示如何设置应用程序以便使用振动效果。您也可以参阅 SDK 示例中 Integration Demo (DemoMotion.cpp) 的 Demo Motion。其中提供有所有支持平台的工作示例。

单人设置

首先,像其他插件一样管理常规插件。您需要包含对应文件,并链接库(仅针对 Wwise 原生开发,在 Unity 上可忽略)。

#include "AkMotionSinkFactory.h" // 链接至 AkMotionSink.lib,并将输出实现输出到游戏控制器。
#include "AkMotionGeneratorSourceFactory.h" // 链接至 AkMotionGenerator.lib,并实现 Motion Generator 源。

然后,使用 Wwise 工程中设置的 Motion ShareSet 名称添加附加输出(在本例中名称为 Wwise_Motion)。因为要使用第一个相连的游戏控制器,所以在此将 0 用作输出 ID。

AkOutputSettings outputSettings("Wwise_Motion", 0);
AK::SoundEngine::AddOutput(outputSettings);

然后,正常播放 Event。在 Wwise 工程中,Play_Explosion 事件指向的 Sound SFX 会输出至将 Wwise_Motion 共享集指派为 Audio Device 的总线。

AkGameObjectID explosionGO = 100;
AK::SoundEngine::RegisterGameObj(explosionGO, "Explosion");
AK::SoundEngine::PostEvent("Play_Explosion", explosionGO);

多人设置

确切地说,多人是指同一主机上的多个玩家,而非网络游戏中的多个玩家。在多人设置中,必须分别设置振动效果或玩家专用输出,以便反映玩家在游戏世界中的视角。为此,每个玩家都需要分别设置 Listener。

int NUM_PLAYERS = 4;
const AkGameObjectID OBJ_FOR_PLAYER[MAX_PLAYERS] = {100 ,200, 300, 400}; // Game Object ID 可以任选。
for(int i = 0; i < NUM_PLAYERS; i++)
{
AK::SoundEngine::RegisterGameObj(OBJ_FOR_PLAYER[i]); // 注册要用作 Listener 的 GameObject。
AK::SoundEngine::SetListeners(OBJ_FOR_PLAYER[i], &OBJ_FOR_PLAYER[i], 1); // 让 Game Object 接收自己发出的声音。
}

然后,为每个玩家添加一个输出。每个 ShareSet 都可多次使用,无需设置多个 ShareSet。不过,需要为每个控制器设置一个实际设备 ID。本例适用于 Windows 上的 Xbox 控制器。有关如何针对特定平台检索设备 ID 的信息,请参阅“motion_application_setup”中的表格。

const AkUInt32 DEVICE_SPECIFIC_ID[MAX_PLAYERS] = {0, 1, 2, 3}; // 对于 Windows 上的 Xbox 控制器,设备 ID 为 0 ~ 3。其他平台有不同的要求。
for(i = 0; i < NUM_PLAYERS; i++)
{
AkOutputSettings settings("Wwise_Motion", DEVICE_SPECIFIC_ID[i]); // 使用 Wwise_Motion 共享集来驱动设备 DEVICE_SPECIFIC_ID[i]。
res = AK::SoundEngine::AddOutput(settings, &motionOutputIDs[i], &OBJ_FOR_PLAYER[i], 1); // 添加输出,并链接相应的 Listener。
}

然后,正常播放 Event。在 Wwise 工程中,Play_GunFire 事件指向的 Sound SFX 会输出至将 Audio Device 指派为 Wwise_Motion 共享集的总线。

AK::SoundEngine::PostEvent("Play_GunFire", OBJ_FOR_PLAYER[0]); // 鉴于 Game Object 和 Listener 的关系,将仅播放玩家控制的 0 号控制器。

若要播放的 Event 会影响多个设备,则需设置新的 Game Object,并将其作用于所有玩家专用 Listener。

AK::SoundEngine::RegisterGameObj(explosionGO, "Explosion"); // 注册要播放爆炸声的 Game Object。
AK::SoundEngine::SetListeners(explosionGO, OBJ_FOR_PLAYER, 4); // 将玩家控制的 4 个 Listener 全部绑定至该 Game Object,以便都能接收 Motion Effect。
AK::SoundEngine::PostEvent("Play_Explosion",explosionGO ); // 因为 4 个 Listener 全部都绑定至 explosionGO,所以 Play_Explosion 事件将广播给所有 Listener。

此外,还可参阅示例 IntegrationDemo 中的 DemoMotion 类。其中提供有多人设置示例。

核对清单与故障排除

为了确保特定设备可使用某个设备接收振动效果,必须执行以下操作:

  • 将 Wwise Motion ShareSet 添加至 Wwise 工程的 Audio Device。
  • 创建顶层 Audio Bus,并将其 ShareSet 设为刚才添加的 Wwise Motion。
  • 创建 Sound SFX 并将其连通至振动总线层级结构。
  • 在游戏中,通过包含 AkMotionSinkFactory.h 来链接 AkMotionSink 库,同时链接 AkMotionSink 库。
  • 使用 AK::SoundEngine::RegisterGameObj 创建要调用和接收振动事件的 Game Object。
  • 使用 Wwise Motion ShareSet 和设备 ID 来调用 Ak::SoundEngine::AddOutput。若为多人设置,请分别提供 Listener 对象。
  • 像音频 Event 一样触发 Event。

在 Wwise 工程中设置 Motion:

  • 将 Wwise Motion ShareSet 添加至 Wwise 工程的 Audio Device。
  • 创建顶层 Audio Bus,并将其 ShareSet 设为刚才添加的 Wwise Motion。
  • 创建 Sound SFX 并将其连通至振动总线层级结构。
  • 在 Audio Preferences 中,找到要使用振动效果的总线,然后从列表中选择设备并将其设为振动设备。

性能分析

为了排除故障,建议先对应用程序进行性能分析。在设计工具中您可以对应用程序做性能分析,方法是连接到应用程序并使用 Profiler 布局 (F6)。 您可以利用各项工具来了解问题的根源。在 Capture Log 视图中,可查看错误代码(显示为红色)。在 Graph 视图中,可查看声音引擎管线的图示。管线末端应会显示振动设备。若不显示,则表示声音引擎无法找到指定的设备。另外,还设有 Emitter/Listener 选项卡视图。在该视图中,将显示所有 Emitter-Listener 组合。若 Motion Effect 出现问题,则表示 Emitter 可能没有关联针对振动设备指定的 Listener。

若触发 Motion Effect 时出现问题,请执行以下操作:

  • 查看 Capture Log,确保插件无注册错误。若无错误,请检查是否已包含 AkMotionSinkFactory.h 并链接至 AkMotionSink 库。
  • 确保声音引擎能够初始化设备。若无法初始化,则从游戏调用 AddOutput 时将在 Capture Log 中显示相应错误。
  • 确保将所播放的 Sound SFX 连通至指向振动设备的总线。为此,请查看 Sound SFX 的 Audio Bus 属性和总线的 Audio Device 属性。
  • 在 Voices Graph 选项卡中,检查触发了哪个 Emitter。确保 Emitter-Listener 选项卡中设有关联的 Listener。该 Listener 可能与发声和收听的 Game Object 相同。若非如此,请检查 RegisterGameObj、SetListeners AddOutput 调用。
  • 确保 Listener 与规定输出设备关联。
  • 同时注意各项 API 调用的结果。确保没有返回任何错误。

对于 Android 设备,请务必在应用程序的 AndroidManifest.xml 文件中添加权限:

<uses-permission android:name="android.permission.VIBRATE"/>