版本

menu_open
警告:此页面上某些受保护的信息未予显示。
若为特定平台的授权用户,请确保已登录相应的帐户。
Wwise SDK 2022.1.18
集成 Wwise Motion

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

振动组件

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

Motion Sink Plug-in

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

Motion 源插件

利用 Motion 源插件,您可以精确地设计触觉反馈效果器的行为。正如其他音频源一样,您可以将 Motion 添加至 Wwise 工程中的 Sound SFX 节点。请确保将 Sound SFX 节点的 Output Bus 设为振动总线。如需了解更多信息,请参阅 Motion

设置振动

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

Wwise 设计工具设置

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

游戏设置

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

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

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

PlatformDeviceDevice Channel Config and LayoutAdditional Requirements
AndroidAndroid device with vibration supportAnonymous 1-channel
iOSNot supported.
LinuxNot supported.
MacNot supported.
OpenHarmonyOpenHarmony device with vibration supportAnonymous 1-channel
PlayStation 4DUALSHOCK 4
PlayStation Move
Anonymous 2-channel:
左侧电机、右侧电机
PlayStation 5DualSense
VR 控制器
Stereo 2-channel:
左侧振动、右侧振动
StadiaStadia 兼容手柄匿名 2 声道:
左侧电机、右侧电机
SwitchJoy-Con匿名 4 声道:
左侧低频振动、左侧高频振动、
右侧低频振动、右侧高频振动
WindowsXbox 和 XInput 兼容控制器
DirectInput 兼容控制器
Anonymous 2-channel:
左侧电机、右侧电机
XInput.lib
Dinput8.lib
Winmm.lib
UWPUWP 手柄匿名 4 声道:
左侧电机、右侧电机、
左侧触发器、右侧触发器
C++/CX
Xbox One
Xbox Series X
Xbox 控制器Anonymous 4-channel:
左侧电机、右侧电机、
左侧触发器、右侧触发器


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

PlatformDeviceInformation
AndroidAndroid device with vibration supportUse 0.
iOSNot Supported-
LinuxNot supported.-
MacNot supported.-
OpenHarmonyOpenHarmony device with vibration supportUse 0.
PlayStation 4DUALSHOCK 4 and PlayStation MoveUse the handle of the device returned by scePadOpen or scePadGetHandle.
PlayStation 5DualSense 和 VR 控制器使用 scePadOpen 或 scePadGetHandle 返回的设备句柄。对于 PSVR2,只需创建一个输出设备(使用左侧或右侧 VR 控制器的句柄),就可在两个 VR 控制器上产生振动。若将设备 ID 指定为 0,则系统只针对无线控制器而不针对 VR 控制器进行初始化。
StadiaStadia 兼容手柄通过 ggp::Gamepad 对象调用 AK::SoundEngine::GetDeviceID 来检索手柄的 DeviceID。
SwitchJoy-Con使用 nn::hid::NpadId 中所需的索引。
WindowsXbox 和 XInput 兼容控制器使用玩家索引 (0 ~ 3)。
WindowsDirectInput 兼容控制器使用 DIDEVICEINSTANCE 中存储的 guidProduct。使用 AK::FNVHash32 生成 guidProduct 哈希值。
UWPUWP 手柄通过调用 AK::GetDeviceIDFromGamepad 来检索手柄的 DeviceID。
Xbox One (XDK)Xbox 控制器使用 IGamepad 对象中存储的 ID。
Xbox One (GDK)
Xbox Series X
Xbox 控制器通过调用 AK::SoundEngine::GetGameInputDeviceID 来检索手柄的 DeviceID。


备注: 在除 Windows 外的所有其他平台上,若直接把设备 ID 指定为 0,将指向第一个支持振动效果的可用设备。

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

多人游戏考量因素

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

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

备注: 即便 Emitter 作为 Listener 采用振动输出,也要将对应的声音连入振动总线层级结构。

示例

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

单人设置

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

#include "AkMotionSinkFactory.h" //Link to AkMotionSink.lib
#include "AkMotionGeneratorSourceFactory.h" //Link to AkMotionGenerator.lib, implements the Motion Generator source.

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

AkOutputSettings outputSettings("Wwise_Motion", 0);

然后,正常播放 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 的信息,请参阅“ 游戏设置 ”中的表格。

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 库。
    备注: 在 Unity 和 Unreal 中,会自动管理插件库。因此,没必要执行上一步骤。
  • 使用 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"/>
AkUInt64 AkGameObjectID
Game object ID
Definition: AkTypes.h:128
AKSOUNDENGINE_API AKRESULT RegisterGameObj(AkGameObjectID in_gameObjectID)
AkUInt32 AkDeviceID
I/O device ID
Definition: AkTypes.h:146
Platform-independent initialization settings of output devices.
#define AKMOTIONSINK_DYNAMIC_LINK_SCEPAD_FUNCTIONS
AKSOUNDENGINE_API AKRESULT SetListeners(AkGameObjectID in_emitterGameObj, const AkGameObjectID *in_pListenerGameObjs, AkUInt32 in_uNumListeners)
#define AKMOTIONSINK_STATIC_LINK_SCEPAD_FUNCTIONS
AKSOUNDENGINE_API AKRESULT AddOutput(const AkOutputSettings &in_Settings, AkOutputDeviceID *out_pDeviceID=NULL, const AkGameObjectID *in_pListenerIDs=NULL, AkUInt32 in_uNumListeners=0)
#define AKMOTION_SCEPAD_HAPTICS_MODE
uint32_t AkUInt32
Unsigned 32-bit integer
AKSOUNDENGINE_API AkPlayingID PostEvent(AkUniqueID in_eventID, AkGameObjectID in_gameObjectID, AkUInt32 in_uFlags=0, AkCallbackFunc in_pfnCallback=NULL, void *in_pCookie=NULL, AkUInt32 in_cExternals=0, AkExternalSourceInfo *in_pExternalSources=NULL, AkPlayingID in_PlayingID=AK_INVALID_PLAYING_ID)

此页面对您是否有帮助?

需要技术支持?

仍有疑问?或者问题?需要更多信息?欢迎联系我们,我们可以提供帮助!

查看我们的“技术支持”页面

介绍一下自己的项目。我们会竭力为您提供帮助。

来注册自己的项目,我们帮您快速入门,不带任何附加条件!

开始 Wwise 之旅