【UE5】Wwise基础(一):创建为UE服务的Wwise工程
游戏音频和电影音频是不一样的,游戏强调的是交互性的音频。电影中音频可以直接在时间轴上播放,但游戏音频与交互强相关,一个音频往往与一个玩家交互或是一个场景事件有关。而对音乐,游戏是无法预测玩家行为的,因此,游戏音乐在处理音乐过渡上会更谨慎,音乐的播放也与Gameplay强相关。因此,游戏的音频如果想要带动玩家的情绪更困难,因为配乐师无法得知音乐播放时具体的画面,但设计精巧的交互音乐不仅同样能带动玩家的情绪,还能给玩家带来爽快的反馈感。
为了满足交互音频的设计,Wwise因应而生。Wwise是目前最广泛使用的游戏音频中间件之一,相比于引擎提供的解决方案,Wwise的工作流更独立,效果更高,而且Wwise收费并不贵。Wwise在你意想不到的任何一个地方都可能出现,经常和引擎与SpeedTree的logo一起登场,基本上就在宣告“我们是3A”。二月份哥们儿买的俩游戏(原子之心/霍格沃茨之遗)都有经典的UE+SpeedTree+Wwise三件套。
没有音频背景的朋友们不用害怕。Wwise关注的是音频如何播放,而非如何制作音频。
Wwise官方提供了101~301系列课程帮助大伙儿入门Wwise,但Wwise官方只提供了与Unity共同开发的系列课程(Wwise 301),本系列文章内容包含Wwise101, 201的所有内容在UE中的使用,相对而言,属于基础篇,适合从未使用过Wwise的朋友和只在Unity中使用过Wwise的朋友。也许会有讲优化和插件开发的进阶篇,但目前,我们只来关注基础内容。
一. 准备工作
首先,我们会使用Wwise 101的课程文件,下载链接在这里。
记得到官网去下载一个Wwise,然后注册一个账号。在UE中创建一个项目,随便命名即可。我使用的版本是5.0.3,Wwise暂时不支持5.1
官网:
我创建了一个第三人称模板项目,命名为WwiseTutorial。
接下来,我们通过在UE中播放一个随机音频来学习如何在UE中使用Wwise
二. 在引擎中导入Wwise插件并链接工程
Wwise中也有“工程”的概念,因此,我们需要将Wwise工程与UE工程链接起来,并且我们需要安装Wwise插件,如果这个东西由用户手动管理的话会很繁琐,好在Wwise为我们提供了自动化。
在Wwise Launcher->Unreal中可以看到你的所有工程,直接Integrate Wwise into Project就可以。
如果没有,可以在这里手动选择,而且也可以在这里建立一个DemoGame方便学习。
完事之后在面板上选择Open in Wwise就可以了。
在项目的Plugins中应该可以看到Wwise了。
三. 关注Wwise Project
我们项目的Wwise工程看起来像这样:
这个面板看起来很复杂,一些胆小的朋友看到就直接劝退了,不过没关系,我们一步一步的解锁它的功能,先从最简单的东西开始。
如果读者已经熟悉Wwise工程了,可以看一下我在文章末尾附上的何如组建3A级Wwise工程,也许会对你有帮助。
我们先关注Audio面板:
在这里,我们看到了很多不同的文件夹,AudioDevice,MasterMixer等等,他们各自对应不同的功能,比如Actor-Mixer Hierarchy一般对应SFX等,Interactive Music Hierarchy一般对应交互化的BGM。
每一个Hierarchy底下都有一个Default Work Unit,你可以把它理解成一个文件夹,文件夹里还有可以有别的文件夹,一个示例如下:
Actor-Mixer Hierarchy
Default Work Unit
Player Work Unit
Footsteps Work Unit
Footsteps Container..
...
...
Battle Work Unit
Weapon Work Unit
...
NPC Work Unit
...我们的教程遵从简单原则,项目组往往有自己的组织规范,如果想学习一下组织规范,可以看文末参考资料内容。
四. 创建我们的第一个SFX
在Actor-Mixer Hierarchy中,对着Default Work Unit右键,New child建立一个Random Container。
一个Random Container包含着一堆SFX,他会随机播放Random Container中的音频。
我们将这个Random Container命名为Gem_breaking,他用来播放宝石魔法释放后宝石碎屑落在地上的声音。
对着我们创建出来的Gem_breaking右键,Import Audio Files,把lession 2中的音频文件Add Files过去
还有一种简单的创建Random Container的方法,直接右键Work Unit,然后Import Audio Files,Add Folder,并选择为Random Container
弄好了之后就可以按小三角播放试试了:
右上角一个Play Type,选择Shuffle的话,那么知道所有的音频都被随机过之前,已经随机到的音频不会再次播放。repeating last则保证最多连续播放一个音频几次。
五. 创建一个Event
我们创建好了一个音频,现在我们要学习一个Wwise的设计理念:音频的播放是基于Event的,一个Event触发一个播放音频的行为,具体播放了哪个,怎么播放,外界无需知道,只需知道触发哪个事件即可。
这种思维非常的游戏化:策划只知道要在挨打的时候播放一个挨打的音效,但音频设计师思考的会更全面:混响?随机?这种思维将两个工作流隔离开来,抽象为事件接口。对于策划,只需要提出播放挨打音频需求,程序根据event的名字调用一下,音频设计师完全不需要关注其他人的工作。
现在,我们试着在Wwise里创建一个Event,他所做的事情就是播放我们刚才的那玩意儿。
跑到Events面板里->Events->Defailt Work Unit创建一个Event,我将其命名为Play_Gem_Breaking
回到Audio,把我们刚刚做的音频拖进中间的面板就好了,可以按下下面的小三角播放一下。
六. 创建SoundBank
SoundBank是Wwise最终到处给引擎的东西,这里面Wwise会做很多东西,比如把Events封装一下等。
此外,你可能在使用很多音频,但这些音频共用了一个音频文件的一部分波段,Wwise会做一些优化,做到只引用,不拷贝。也有可能,音频的某个波段始终没有被任何Audio引用(由于音频剪辑),Wwise会帮你删掉。
我们来到这里创建一个SoundBank,命名为SB_test
仿照之前的步骤,把我们的Event拖进去:
右键,Generate一下,我这里只Generate了Win平台。
一般的,生成的结果路径为GameDir//_WwiseProject/GeneratedSoundBanks中
六. 在Unreal Engine中播放它
在UE中使用Wwise比Unity更简单:打开项目,在Project Setting中找到Wwise
将Auto connect To WAAPI勾开。
来到Integration Settings中,将Wwise AudioLink Enabled勾开,重启编辑器
把Intergration Settings中的Generated Sound Banks Folder设置为我们刚刚提到的Soundbank生成路径。
在UE的编辑器中选择->窗口->WWise Picker
我们已经看到我们的Play_Gem_Breaking事件了,你可以把它拖到Content Browser中:
然后,我们可以在蓝图中播放他,很简单,但这里我们皮一下,使用动画通知,WWise插件帮我们做了一个简单的通知,当然兄弟们也可以自己实现,反正实现AnimNotify很简单,在动画MF_Run_Forward中:
播放动画试试,在浏览窗口就可以听到音频了,听不到的话检查一下音响有没有插电。
我们来看一下AnimNotify_AkEvent的内容吧:
除去报错信息,AnimNotify_AkEvent是这样处理的:
音频需要跟随物体运动吗?
否:在对应位置播放
是:检查是否有Ak Component
没有:摆烂,报错
有:可用吗?
不可用:摆烂,报错
可用:播放音频,并且音频跟随组件他还有一种播放音频的方法是直接PostEvent,但是我们看它的源码可以知道,如果找不到AkComponent,他也会摆烂不播了:
AkPlayingID PostEvent(UObject * Object, FAkAudioDevice * AudioDevice, FWwiseEventTracker & EventTracker, float CurrentTime)
{
ensure(AudioDevice != nullptr);
if (EventTracker.EventName.IsEmpty())
{
UE_LOG(LogAkAudio, Warning, TEXT("Attempted to post an AkEvent from an empty Sequencer section."));
return AK_INVALID_PLAYING_ID;
}
if (Object && AudioDevice)
{
auto AkComponent = Cast<UAkComponent>(Object);
if (!IsValid(AkComponent))
{
auto Actor = CastChecked<AActor>(Object);
if (IsValid(Actor))
{
AkComponent = AudioDevice->GetAkComponent(Actor->GetRootComponent(), FName(), NULL, EAttachLocation::KeepRelativeOffset);
}
}
if (IsValid(AkComponent))
{
AkPlayingID PlayingID;
if (EventTracker.Event)
{
PlayingID = EventTracker.Event->PostOnComponent(AkComponent, nullptr, &FWwiseEventTracker::PostEventCallbackHandler, &EventTracker, (AkCallbackType)(AK_EndOfEvent | AK_Duration), nullptr, AkComponent->StopWhenOwnerDestroyed);
}
else
{
const AkUInt32 ShortID = AudioDevice->GetShortID(nullptr, EventTracker.EventName);
PlayingID = AudioDevice->PostEventOnAkComponent(ShortID, AkComponent,
AkCallbackType::AK_EndOfEvent | AkCallbackType::AK_Duration,
&FWwiseEventTracker::PostEventCallbackHandler, &EventTracker);
}
if (PlayingID != AK_INVALID_PLAYING_ID)
{
AkComponent->SetStarted(true);
}
EventTracker.TryAddPlayingID(PlayingID);
if (EventTracker.IsDirty)
LogDirtyPlaybackWarning();
return PlayingID;
}
}
return AK_INVALID_PLAYING_ID;
}
可以看到如果AkComponent = AudioDevice->GetAkComponent(Actor->GetRootComponent(),FName(),NULL, EAttachLocation::KeepRelativeOffset);执行之后如果AkCompoennt还是为空就啥也不干了。
这种设计被Wwise官方称为基于GameObject的设计(这命名,难怪官方只有Unity教程),它的好处就是它可以实时计算播放音频的游戏物体的状态,使用它的信息,如位置,遮挡等。同时,它也可以用来处理一些边际条件,比如在说话的NPC被打死了之类的。
七. 推荐阅读
突然发现资料忘记贴了,补上:
如何创建一个3A级别的Wwise工程
Wwise 301
Wwise 201
Wwise 101 正好要开始搞wwise,感谢分享[干杯] 很高兴帮到你[爱] 想请教下,generate sound data并不会自己创建asset,需要从picker里手动拖到unreal里是吗? 是的 修改音量使用哪个api呢set rtpc value吗 用RTPC可以的
页:
[1]