版本

menu_open
Wwise Unity Integration Documentation
使用 C# 代码来控制声音引擎

大多数 Wwise SDK 函数可以通过 AkSoundEngine 类在 Unity 中使用。将它想象为 C++ 命名空间 AK::SoundEngine、AK::MusicEngine 等等的替代。See API Limitations for changes made in the API binding compared to the original SDK. 对于更复杂的情况,您需要从代码中调用 Wwise 函数。在 API 中,所有函数中的 GameObjectID 被Unity 风格的 GameObject 所替代。在运行时,这个 GameObject 中将自动添加一个 AkGameObj 组件,除非您之前已经手动添加过了。

对于 Event 和 Bank 使用数字 ID,而不是字符串。

原生 Wwise API 使用字符串或 ID 来触发 Wwise 工程中的事件和其它有名字的对象。您仍然可以在 C# 环境下这样做,方法是将文件 Wwise_IDs.h 转码为 Wwise_IDs.cs。点击 Assets > Wwise > Convert Wwise SoundBank IDs。为了完成上述操作,您需要安装 Python。

将 MIDI 发送到 Wwise

如需将 MIDI 发送到 Wwise,可为 AkMIDIPostArray 类的 AkMIDIPost 成员赋值,并调用以下任一方法:

以下是一个将 MIDI 消息发送到声音引擎的简单脚本:

public class MyMIDIBehaviour : UnityEngine.MonoBehaviour
{
public AK.Wwise.Event SynthEvent;
private void Start()
{
AkMIDIPostArray MIDIPostArrayBuffer = new AkMIDIPostArray(6);
AkMIDIPost midiEvent = new AkMIDIPost();
midiEvent.byType = AkMIDIEventTypes.NOTE_ON;
midiEvent.byChan = 0;
midiEvent.byOnOffNote = 56;
midiEvent.byVelocity = 127;
midiEvent.uOffset = 0;
MIDIPostArrayBuffer[0] = midiEvent;
midiEvent.byOnOffNote = 60;
MIDIPostArrayBuffer[1] = midiEvent;
midiEvent.byOnOffNote = 64;
MIDIPostArrayBuffer[2] = midiEvent;
midiEvent.byType = AkMIDIEventTypes.NOTE_OFF;
midiEvent.byOnOffNote = 56;
midiEvent.byVelocity = 0;
midiEvent.uOffset = 48000 * 8;
MIDIPostArrayBuffer[3] = midiEvent;
midiEvent.byOnOffNote = 60;
MIDIPostArrayBuffer[4] = midiEvent;
midiEvent.byOnOffNote = 64;
MIDIPostArrayBuffer[5] = midiEvent;
SynthEvent.PostMIDI(gameObject, MIDIPostArrayBuffer);
}
}

在 Unity 中进行离线渲染

Unity 集成暴露了 Wwise SDK 中的离线渲染功能并简化了音频样本的检索方式。

注意: 务必确保在启用离线渲染时仅从主线程中异步调用 AkSoundEngine.LoadBankAkSoundEngine.UnloadBank API。有关详细信息,请参阅自由调度音频渲染任务章节。

AkSoundEngine.StartDeviceCapture 会设置用于捕获的特定输出音频设备,以便通过调用 AkSoundEngine.UpdateCaptureSampleCount 来确定可用样本数,并通过调用 AkSoundEngine.GetCaptureSamples 来检索音频样本数。

以下示例阐释了如何使用 Unity 集成来结合 Unity 的屏幕捕获功能执行离线音频渲染。在实现此功能后,可轻松执行多路复用后期处理步骤,并将捕获的音频样本和视频帧合并为电影文件。

public abstract class WwiseOfflineRenderer : UnityEngine.MonoBehaviour
{
public bool IsOfflineRendering { get; set; }
public bool StartWithOfflineRenderingEnabled = false;
private bool IsCurrentlyOfflineRendering = false;
public float FrameRate = 25.0f;
protected ulong OutputDeviceId = 0;
public abstract string GetUniqueScreenshotFileName(int frameCount);
public abstract void ProcessAudioSamples(float[] buffer);
protected void Start()
{
OutputDeviceId = AkSoundEngine.GetOutputID(AkSoundEngine.AK_INVALID_UNIQUE_ID, 0);
if (StartWithOfflineRenderingEnabled)
{
IsOfflineRendering = true;
Update();
}
}
private void LogAudioFormatInfo()
{
var sampleRate = AkSoundEngine.GetSampleRate();
var channelConfig = new AkChannelConfig();
var audioSinkCapabilities = new Ak3DAudioSinkCapabilities();
AkSoundEngine.GetOutputDeviceConfiguration(OutputDeviceId, channelConfig, audioSinkCapabilities);
UnityEngine.Debug.LogFormat("Sample Rate: {0}, Channels: {1}", sampleRate, channelConfig.uNumChannels);
}
protected void Update()
{
if (IsOfflineRendering != IsCurrentlyOfflineRendering)
{
IsCurrentlyOfflineRendering = IsOfflineRendering;
if (IsOfflineRendering)
{
#if UNITY_EDITOR
// 确保 Editor 更新不会调用 AkSoundEngine.RenderAudio()。
AkSoundEngineController.Instance.DisableEditorLateUpdate();
#endif
LogAudioFormatInfo();
AkSoundEngine.ClearCaptureData();
AkSoundEngine.StartDeviceCapture(OutputDeviceId);
}
else
{
AkSoundEngine.StopDeviceCapture(OutputDeviceId);
#if UNITY_EDITOR
// 恢复 Editor 更新对 AkSoundEngine.RenderAudio() 的调用。
AkSoundEngineController.Instance.EnableEditorLateUpdate();
#endif
}
}
var frameTime = IsOfflineRendering && FrameRate != 0.0f ?1.0f / FrameRate : 0.0f;
UnityEngine.Time.captureDeltaTime = frameTime;
AkSoundEngine.SetOfflineRenderingFrameTime(frameTime);
AkSoundEngine.SetOfflineRendering(IsOfflineRendering);
if (!IsOfflineRendering)
return;
UnityEngine.ScreenCapture.CaptureScreenshot(GetUniqueScreenshotFileName(UnityEngine.Time.frameCount));
var sampleCount = AkSoundEngine.UpdateCaptureSampleCount(OutputDeviceId);
if (sampleCount <= 0)
return;
var buffer = new float[sampleCount];
var count = AkSoundEngine.GetCaptureSamples(OutputDeviceId, buffer, (uint)buffer.Length);
if (count <= 0)
return;
ProcessAudioSamples(buffer);
}
}

在 Unity 中使用 Audio Input 源插件

您可以通过 C# 脚本来调用 Audio Input 源插件。请参阅 Audio Input Source Plug-in from the Wwise SDK documentation.

以下是一个将测试音发送到 Audio Input 源插件的简单脚本:

public class MyAudioInputBehaviour : UnityEngine.MonoBehaviour
{
public AK.Wwise.Event AudioInputEvent;
public uint SampleRate = 48000;
public uint NumberOfChannels = 1;
public uint SampleIndex = 0;
public uint Frequency = 880;
private bool IsPlaying = true;
// 通过该回调填充音频采样 – 此函数会在每一帧针对各声道调用。
bool AudioSamplesDelegate(uint playingID, uint channelIndex, float[] samples)
{
for (uint i = 0; i < samples.Length; ++i)
samples[i] = UnityEngine.Mathf.Sin(Frequency * 2 * UnityEngine.Mathf.PI * (i + SampleIndex) / SampleRate);
if (channelIndex == NumberOfChannels - 1)
SampleIndex = (uint)(SampleIndex + samples.Length) % SampleRate;
// 返回 false 表示已无更多数据可提供。与此同时,会停止关联事件。
return IsPlaying;
}
// 通过该回调设置音频格式 - 在请求提供样本之前会调用此函数一次。
.
audioFormat.channelConfig.uNumChannels = NumberOfChannels;
audioFormat.uSampleRate = SampleRate;
}
private void Start()
{
// The AudioInputEvent event, that is setup within Wwise to use the Audio Input plug-in, is posted on gameObject.
// 调用 AudioFormatDelegate 一次,并在每一帧调用 AudioSamplesDelegate 一次,直到返回 false。
AkAudioInputManager.PostAudioInputEvent(AudioInputEvent, gameObject, AudioSamplesDelegate, AudioFormatDelegate);
}
// 可通过其他脚本调用此方法以停止回调
public void StopSound()
{
IsPlaying = false;
}
private void OnDestroy()
{
AudioInputEvent.Stop(gameObject);
}
}

在 Unity 中应用自定义定位

在默认情况下,会将 AkGameObj 组件关联到特定的 Unity gameObject ,并使用其变换功能(可选偏置)进行全面定位。这对很多游戏(如第一人称射击游戏)来说基本上就够了。不过,对于采用自定义镜头角度的游戏(如各种第三人称游戏)来说,假如只是简单地将音频听者关联到单个游戏对象(如 Unity 中的主镜头),定位的距离衰减和空间化这两个方面可能会不好协调。其他游戏可能还要给玩家提供别的自定义定位体验。

为此,AkGameObj 组件类允许用户重写定位。通过 GetPosition()、 GetForward()GetUpward() 这三种虚方法,用户可选择继承 AkGameObj 的子类,并使用这些子类组件来灵活地自定义任意数量 Unity gameObject 的定位。

这里有一个简单的示例,展示了如何使用自定义组件来重写默认的 AkAudioListener 行为。对这个整合了 Wwise 的第三人称游戏项目,可移除现有的 AkAudioListener 及其关联的 AkGameObj 。然后,将以下脚本关联到 MainCamera 对象,并关联 AkAudioListener 。最后,指定音频听者位置所要跟随的目标 gameObject (如玩家角色)。如此一来,所有发声体的距离衰减都会将所选目标 Unity gameObject 的位置作为听者位置(画面内的距离听者),而所有发声体的朝向仍会将主镜头朝向作为听者朝向(画面外的朝向听者)。

#if !(UNITY_DASHBOARD_WIDGET || UNITY_WEBPLAYER || UNITY_WII || UNITY_WIIU || UNITY_NACL || UNITY_FLASH || UNITY_BLACKBERRY) // Disable under unsupported platforms.
//
// Copyright (c) 2017 Audiokinetic Inc. / All Rights Reserved
//
using UnityEngine;
using System;
using System.Collections.Generic;
[AddComponentMenu ("Wwise/AkGameObj3rdPersonCam")]
[ExecuteInEditMode] // 需要通过 ExecuteInEditMode 来正确维护 isStaticObject 的状态。
public class AkGameObj3rdPersonCam : AkGameObj
{
public Transform target; // 指定此镜头所要跟随的位置。用户可在 Inspector 中将其指定为玩家角色的 Unity gameObject。
// 将镜头位置设为玩家位置,据此处理距离衰减。
public override Vector3 GetPosition ()
{
return target.GetComponent<AkGameObj> ().GetPosition ();
}
}
#endif // #if !(UNITY_DASHBOARD_WIDGET || UNITY_WEBPLAYER || UNITY_WII || UNITY_WIIU || UNITY_NACL || UNITY_FLASH || UNITY_BLACKBERRY) // Disable under unsupported platforms.
Definition: AkWwiseAcousticTexture.cs:21
This type can be used to post Events to the sound engine.
Definition: AkWwiseEvent.cs:29
This component represents a sound object in your scene and tracks its position and other game syncs s...
Definition: AkGameObj.cs:32
Definition: AkWwiseAcousticTexture.cs:21
virtual UnityEngine.Vector3 GetPosition()
Definition: AkGameObj.cs:272

此页面对您是否有帮助?

需要技术支持?

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

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

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

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

开始 Wwise 之旅