Quantcast
Channel: 英特尔开发人员专区文章
Viewing all articles
Browse latest Browse all 583

如何使用 Unreal Engine* 构建自定义音频编辑器,在虚拟现实中实现音效空间化

$
0
0

woman in a virtual environment

概述

Epic Games 的 Unreal Engine*拥有一个强大的虚拟现实 (VR) 编辑器选项,但是该选项不具备在虚拟现实中编辑与放置音效的能力。调整音效后,必须不断重启编辑器,才能测试虚拟现实中的音效,这是件非常麻烦的事。因此,我们决定创建一款音效编辑器,以支持游戏开发人员与音效设计师在虚拟现实中快速放置、编辑与测试空间化音效。This will prevent the user from having to constantly enter and exit the editor.

woman in a virtual environment

系统要求

  • Unreal Engine 4.18.1 或更高版本
  • Visual Studio* 2017
  • HTC Vive*

您将学到的知识

  • 动作控制器交互
  • 如何创建一个自定义 C++ 类
  • VR UI
  • 保存编辑器修改
  • 音效空间化参数

下面,我们将从头到尾逐步介绍如何创建这款面向 Unreal Engine 的自定义音频编辑器工具:

项目链接下载

开始前,您需要做几件事。下载并解压项目文件夹。您还需要确保已安装 Unreal Engine 4.18.1 或更高版本。

下载并解压文件夹后,右击 Intel_VR_Audio_Tools.uproject 并选择“生成 Visual Studio 项目文件”(Generate Visual Studio project files)。完成后,打开项目。将出现“缺少 Intel_VR_Audio_Tools 模块”的弹出消息。单击“是”开始重新创建;应该耗时不到 20 秒。鉴于您动态查找添加至项目的 .wav 文件的方式,这是必要的,我们将在自定义 C++ 类章节中予以介绍。

设置虚拟现实播放器

我们首先从 Unreal 虚拟现实模板开始,选择 MotionControllerPawn 作为我们的 pawn,它的动作控制已设置,并支持通过远距传动移动。

动作控制器交互

动作控制器与 3D 小部件交互前,需要将 WidgetInteraction 组件添加至 VirtualRealityBP 文件夹中的 BP_MotionController。我们还需要为音效选择器小部件添加一个名为 soundScene 的场景组件。

widget, motion controller options screenshot

右触发器被启动时,Press 和 Release Pointer key 连接调用的事件。我们需要增加 MotionControllerPawn,它也位于 VirtualRealityBP 文件夹中。

screenshot of widget interaction with right controller

自定义 C++ 类

制作教程时,了解音效的名称和位置以及动态更新小部件以匹配所有文件是一个难以解决的问题,因此,需要重建项目。幸运的是,Unreal Engine 为我们提供了一些帮助。

IntelSoundComponent 是一个可以添加至任意蓝图的 C++ 类,用于动态定位与加载 .wav 文件至 USoundWave,Unreal 也是通过这种方式加载音效文件。

首先,右击内容浏览器并创建一个名为 IntelSoundComponent 的新 C++ 类。该操作创建了一个 IntelSoundComponent.cpp 文件和 IntelSoundComponent.h 文件。

接下来,我们添加定位与管理文件所需的 include。

在 IntelSoundComponent.cpp 中添加了 Paths.h, FileManager.h 和 Runtime/Engine/Classes/Sound/SoundWave.h(因为某些原因,SoundWave.h 前面的部分必不可少)两种 Include。

#include "IntelSoundComponent.h"
#include "Paths.h"
#include "FileManager.h"
#include "Runtime/Engine/Classes/Sound/SoundWave.h"

bool exists;
FString dir, soundDir;
TArray<FString> soundFiles;

// Sets default values for this component's properties
UIntelSoundComponent::UIntelSoundComponent()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = true;

	//Empty soundFiles TArray.Easiest way if new wave files are added.
	soundFiles.Empty();

	//the way Unreal Engine calls the project's root directory
	dir = FPaths::ProjectDir();

	//Combining Root with the folder location for the sounds.
	//This could probably be an external folder if needed with the help of ( IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile(); )
	soundDir = dir + "Content/Sounds";

	//UE4 returns a bool if the directory exists or not.
	exists = FPaths::DirectoryExists(soundDir);

}

代码块。IntelSoundComponent.cpp

现在,我们创建了一个名为 exists 的 bool、两个名为 dir 和 SoundDir 的 FString 变量和一个名为 soundFiles 的 FString TArray。由于 soundFiles 是一个 TArray,我们可以通过调用 soundFiles.Empty() 来清空 TArray。我们相信如果添加了新波形文件,这也是最快的方法。然后,我们将 FString dir 设置为 FPaths::ProjectDir();(提供了项目的根位置)。接下来,我们将 FString soundDir 设置为 dir + "Content/Sounds”,因为它是我们放置 .wav 文件的文件夹。FPaths 可以通过其他方法来检查目录是否存在,因此,我们将 bool 设置为 exists = FPaths::DirectoryExists(soundDir);。

// Called when the game starts
void UIntelSoundComponent::BeginPlay()
{
	Super::BeginPlay();

	//UE4 way of managing files
	IFileManager &fileManager = IFileManager::Get();

	//UE_LOG(LogTemp, Warning, TEXT("%s"), &fileManager);


	if (exists == true){

		//Extensions to sound files.Was using .wav, but .uasset seems to work when there is and isn't an editor.
		FString ext = "/*.wav";
		FString ext2 = "/*.uasset";

		//path = FPaths::ProjectDir() + Content/Sounds + /*.uasset
		FString path = soundDir + ext2;

		//This finds file in the given array, with the given path
		//the true bool is saying to look for files while false bool is saying to not look for directories
		fileManager.FindFiles(soundFiles, *path, true, false);

代码块。IntelSoundComponent.cpp

在 BeginPlay() 上,我们首先使用 IFileManager &fileManager = IFileManager::Get(); 对 IFileManager 进行实例化。我们的目标是调试与测试 .wav 文件是否能被 fileManager.FindFiles 发现,后者搜索 .uassets,而不是我们之前使用的 .wav 文件,因为 .uassets 在共享项目时更可靠。

//Setting soundFileArray to soundFiles to pass into blueprint.
void UIntelSoundComponent::soundArray(TArray<FString> &soundFileArray) {

	soundFileArray = soundFiles;

}

//loading a wav file as a USoundWave so Unreal can set the sound chosen with LoadObject<USoundWave> for blueprint
USoundWave* UIntelSoundComponent::setWavToSoundWave(const FString &fileName) {

	USoundWave* swRef;
	FString name = fileName;

	swRef = LoadObject<USoundWave>(nullptr, *name);

	return swRef;

}

代码块。IntelSoundComponent.cpp

最后,我们在 .cpp 中创建了显示为蓝图节点的两个函数。它们是 SoundArray(将 soundFiles TArray 传输至蓝图)和 setWavToSoundWave(我们花了一些时间才弄清楚,因为我们需要找到一个动态引用 .wav 文件的方法,这个方法必须为 Unreal 所理解,它是一个 USoundWave)。为了解决该问题,我们发现了 LoadObject。如果条件允许的话,该函数在运行时将对象加载至我们设置的任何类型。对我们而言,它是 LoadObject(nullptr, *name);—*name 是虚拟现实玩家选择的音效。

我们在 IntelSoundComponent.h 中创建了两个 UFUNCTION,以调用 .cpp 蓝图中的两个函数。

#include "CoreMinimal.h"
#include "Components/SceneComponent.h"
#include "Runtime/Engine/Classes/Sound/SoundWave.h"
#include "IntelSoundComponent.generated.h"



UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class INTEL_VR_AUDIO_TOOLS_API UIntelSoundComponent : public USceneComponent
{
	GENERATED_BODY()


public:
	// Sets default values for this component's properties
	UIntelSoundComponent();

	//Blueprint function to expose soundFiles into blueprint.
	UFUNCTION(BlueprintCallable, Category = IntelAudio)
		void soundArray(TArray<FString> &soundFileArray);

	//Blueprint function passing a wav converted in USoundwave into blueprint.
	UFUNCTION(Category = IntelAudio, BlueprintCallable)
		USoundWave* setWavToSoundWave(const FString &fileName);

代码块。IntelSoundComponent.h

向蓝图展示音效文件的蓝图函数。

screenshot of sound array widget

传输 .wav 文件的蓝图函数在 USoundWave 中被转换为蓝图。

screenshot of sound widget

设置 UI

我们需要设置 3 个 UMG 小部件。

screenshot of multiple widget set up

我们创建了用于管理这些 UMG 小部件的蓝图。

screenshot of multiple blue prints to manage umg widgets

我们为该项目配备了若干个小部件。选择音效后,AudioParamsSliderWidget 小部件将弹出。soundButtonWidgetBP 只是面向 Content/Sound 文件夹中音效的按钮部件。我们将 soundSelectorWidgetBP 小部件放在关卡中,具体方法创建一个名为 IntelSoundWidgetBP 的 actorBP,并使其获取来自 SoundArray C++ 节点的音效,然后使用 soundButtonWidgetBP 来填充 soundSelectorWidgetBP。(我们可以动态地完成,但是每次开始播放时,我们都会获得新生成的 actor 的引用。)这一切都发生在 IntelSoundManagerBP 中,我们从一开始也把它放在关卡中。

screenshot of sound widget
IntelSoundManagerBP

我们从上图中获取了 FString 的 soundFiles TArray,与此同时,分割.wav 的名称(音效名称)。我们将该字符串发送至 IntelSoundWidget 的字符串列,以命名动态填充的按钮。

screenshot of sound widget
IntelSoundWidgetBP

我们在 IntelSoundWidgetBP 中生成 soundUI,

screenshot of sound widget

添加音效,

screenshot of sound widget

如果我们不使用 Set Widget 节点,将生成小部件,但是它在游戏中不可见。

screenshot of sound widget spawned in VR environment

音效参数

玩家从小部件中选择音效后,将生成一个 IntelSoundAudioActorBP actor。我们在 actor 中看到了 AudioParamsSliderWidgetBP,如果单击 Spatialize?,将显示 3 个衰减设置,可以通过小部件对它们进行修改。

screenshot of sound widget - volume settings

screenshot of sound widget - volume settings

声音衰减本质上是指随着玩家的离开,音量减弱的能力。

graph

 

graph

graph

 

graph

显示的 3 个设置为衰减函数、衰减形状和衰减距离。

如果时间充足,可以显示更多设置。Unreal 中存在衰减设置结构的映像。

Unreal* attenuation settings

我们相信我们选择的 3 个设置是最基本、最需要的设置。我们现在正在研究如何在改变设置时显示调试行。我们正在尝试使用衰减设置调试行 Unreal 用例来显示游戏编辑器中的衰减,但是还未找到答案。因此,我们可能得到所选的衰减形状和函数的形状范围,并使用 Unreal 内置绘制调试行节点。

退出时保存

当我们退出游戏,生成了音效,移动它们并且运行了音频参数时,我们通过 IntelSoundAudioActorBP,使用 IntelSaveGameBP 保存所有重要的变量。

variables save UI
IntelSaveGameBP

screenshot of sound manager blueprint
IntelSoundManagerBP

screenshot of audio actor blueprint
IntelSoundAudioActorBP

如果一切正常运行,我们应该能够在虚拟现实中编辑文件夹中的任何音效。


Viewing all articles
Browse latest Browse all 583

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>