目次

Wwise SDK 2019.2.9
リスナーの統合

イントロダクション

リスナーは、ゲーム内のマイクの位置を表すゲームオブジェクトです。ゲームオブジェクトをリスナーとして指定することで、3Dサウンドを実際の3D環境を模倣するためにスピーカーに割り当てることができます。同様に、エミッタゲームオブジェクトは仮想スピーカーを表し、リスナーに割り当てられると、エミッタの位置情報がリスナーの座標系にマッピングされて3Dサウンドをレンダリングします。エミッターまたはリスナー(またはその両方)として機能するかどうかにかかわらず、Wwiseのゲームオブジェクトには、位置ベクトルである正面および上方向のベクトルだけでなく、変換も割り当てられます。サウンドが正しいスピーカーを通してレンダリングされるように、ゲームオブジェクトの変換を各フレームで更新する必要があります。

リスナーの登録

音を聞くには、少なくとも1つのゲームオブジェクトを登録してリスナとして割り当てる必要があります。他のすべてのゲームオブジェクトにリスナーを割り当てるには AK::SoundEngine::SetDefaultListeners を使うか、特定のゲームオブジェクトにリスナーを割り当てるため、また、 AK::SoundEngine::SetDefaultListeners を使用して設定されているものを上書きするために、 AK::SoundEngine::SetDefaultListeners を使うことができます。ゲームオブジェクトを登録し、デフォルトのリスナーとして割り当てる方法は次のとおりです:

AkGameObjectID MY_DEFAULT_LISTENER = 0;
// Register the main listener.
AK::SoundEngine::RegisterGameObj(MY_DEFAULT_LISTENER, "My Default Listener");
// Set one listener as the default.
AK::SoundEngine::SetDefaultListeners(&MY_DEFAULT_LISTENER, 1);
// Register a game object for playing sounds
AkGameObjectID MY_EMITTER = 1;
AK::SoundEngine::RegisterGameObj(MY_EMITTER, "My Emitter");
// At this point "My Emitter" has 1 listener, "My Default Listener", because we designated it as the default listener.
AkGameObjectID MY_LISTENER_NO2 = 2;
AK::SoundEngine::RegisterGameObj(MY_LISTENER_NO2, "My Listener #2");
// If we want to change the listener for only "My Emitter", we do so as follows:
AK::SoundEngine::SetListeners(MY_EMITTER , &MY_LISTENER_NO2, 1);
// この時点で "My Emitter" には、リスナー "My Listener #2" があります。他のすべてのゲームオブジェクトには、引き続き、リスナーとして "My Default Listener" があります。

WwiseオーサリングツールのAdvanced ProfilerのEmitter-Listenerタブを調べることで、コードで割り当てられたエミッタ・リスナーの関連付けを調べることができます。単純なゲームは、すべてのゲームオブジェクトのデフォルトのリスナとして1つのゲームオブジェクトを選択します。 ただし、複数のリスナーを使用して単一の出力デバイスに出力することは可能です。下記の Multiple Listeners In A Single Output Device 1つの出力デバイス内の複数のリスナー を参照してください。サブミックスの3D配置にリスナーを使用することも可能です。これを行うには、ゲームオブジェクトにリスナーを割り当てて、エミッタ・リスナーの関連付けによって接続されたゲームオブジェクトの有向グラフを作成するリスナーであるリスナーを割り当てる必要があります。

リスナーの位置情報を設定

AK::SoundEngine::SetPosition() 関数は、すべてのゲームオブジェクトと同様に、リスナーの位置を設定するために使用されます。これは、リスナーの位置または方向ベクターのいずれかが変更されるたびに実行される必要があります。

AkTransform listenerTransform;
(... set the position and orientation members of listenerTransform here...)
AK::SoundEngine::SetPosition( listenerPosition );

AkTransformクラスは、ゲームの3D空間におけるリスナーの位置と向きを定義する情報を保持します。リスナーの位置(Position)、OrientationFront、およびOrientationTopベクトルは、 AkTransform クラスのgetterとsetterを使用して、アクセスおよび設定できます。

注釈: OrientationFront (前方向)ベクターは、リスナーの顔の向きを定義します。これは、リスナーの頭の傾斜を定義するOrientationTop(上部方向)ベクターに対して直角であるべきです。リスナーが人間であれば、OrientationFront ベクターがリスナーの鼻の向き(顔から外へ向かっている)となり、OrientationTop ベクターはそれに対して直角関係にあり、リスナーの目の間、額を越えて、さらに上昇します。

Wwiseサウンドエンジンで、X、Y および Z軸がどのように定義されるかについての詳細は X-Y-Z座標系 を参照してください。

方向ベクターは、オーディオが適切にレンダリングされるように定義されなければなりません。それらはゼロベクトルではなく、単位ベクトルである必要があります。また、直角にする必要があります。

注釈: リスナーの位置は、フレームごとに最大で1度更新されます。AK::SoundEngine::SetPosition() 関数への複数の呼び出しが行われても、 AK::SoundEngine::RenderAudio() の呼び出し時には、最後の値のみが考慮されます。
Tip: 例えば、左のスピーカーから聞こえるはずの音が右のスピーカーで聞こえるなど、予想外のサウンドレンダリングが発生している場合、 AK::SoundEngine::SetPosition() 関数を介してサウンドエンジンに提供されるリスナーの位置情報を確認してください。その場合、既知の一定のリスナー位置を設定して、レンダリングが適切であるか確認し、X、Yおよび Z軸に発生している混同を排除することができます。この詳細については、X-Y-Z座標系 を参照してください。

Multiple Listeners In A Single Output Device 1つの出力デバイス内の複数のリスナー

ゲーム内での視野が1つのみのシングルプレイヤーゲームでは、リスナーは1つで十分です。しかしながら、同じシステム上で複数のプレイヤーがプレイできるゲームや、同時に複数の視点が表示される場合には、それぞれの視点にオーディオが適切にレンダリングされるよう、各視点ごとにリスナーが必要になります。

複数リスナーの実装に伴う主な難点は、サウンドソースの位置づけが、実際にプレイヤーが見ているものと調和しない場合があるということです。ほとんどのケースでは、複数プレイヤー向けの3D環境を再現するために単一のスピーカーセットのみを使用するゲームでこのような問題が発生します。

この問題を簡単に表現したのが以下の図です。リスナー0 には左のスピーカー、リスナー1 には右のスピーカーからソースが聞こえるように想定されているので、どのスピーカーでソースが再生されるべきかを知るのは非常に困難です。

異なるスピーカーで同じソースを聞く2つのリスナー

Wwiseのリスナーに上限はなく、デフォルトで全てのリスナーがメインアウトプットデバイスにミキシングされますが、以下は例外です。

次のセクションでは、すべてのリスナーが同じ出力デバイスに統合されるケースについて説明し、Wwiseサウンドエンジンを使用してプログラマーがこれらのリスナーを操作して期待される動作を実現する方法について説明します。

注釈: 複数リスナーに関連する操作は、SDK を介したゲームプログラマーによる実装によってのみ可能です。Wwise オーサリングアプリケーションには、複数リスナーのためにソースのゲーム内ポジショニングを管理する特別なオプションはありません。

複数リスナー:ソースのキャプチャ

各リスナーはミキシンググラフを生成します。ソースがアクティブになっている各リスナーに対して相対的にソースごとの距離とコーン減衰が個別計算されます。

ボリューム減衰の管理

複数のリスナーがソースを取得する場合、ソースはそれぞれのリスナーに対応するそれぞれのバスのインスタンスで順番に混合されます。それが混合されるにつれて、減衰量はそれぞれのリスナーに対して独立して適用されます。

LPF 減衰管理

減衰量とは対照的に、減衰LPFおよびHPFは、ソースに直接適応されます。 したがって、Wwiseは、特定のソースのすべてのエミッタ・リスナーの関連付けに基づいて単一の値を選択する必要があります。各ソースに適用する最終のローパスフィルターをサウンドエンジンが計算する方法は以下のとおりです:

  1. 該当ソースがアクティブになっている各リスナーに対して:
    1. ソースと該当リスナー間の距離に基づいて LPF を計算する
    2. ソースと該当リスナーのなす角度に基づいて LPF を計算する
    3. 2つの値のうち最も高いほうを保持する
  2. 全てのリスナーの中で最も低い値を取得し、オブジェクトの LPF(正則値とRTPC)を追加する

次の表で説明されている例では、リスナー0 の値は max( 10, 40 ) = 40、リスナー1 の値は max( 50, 10 ) = 50 です。2つのうち最も低いのは40で、これがオブジェクトの値5に追加され、最終的な値が45になります:

リスナー 0
リスナー 1
オブジェクト
ソースの
最終 LPF
コーン LPF
半径 LPF
コーン LPF
半径 LPF
10 40 50 10 5 45

ボリュームオフセットと空間化

3D Spatialization では、音とリスナーの位置関係に基づいて、複数のスピーカーに音がパンニングされます。

しかし、2人のプレイヤーによって分割画面でゲームがプレイされる場合、各リスナーに対するサウンドの位置に基づいた、通常通りのスピーカーへのサウンドポジショニングを完全に回避して、リスナー1(1人目のプレイヤー)を左のスピーカー、リスナー2(2人目のプレイヤー)を右のスピーカーで聞こえるようにしたいかもしれません。

ゲームプログラマーは、Wwiseを介して特定のリスナー向けの空間化を無効にし、各チャンネルに対するカスタムのボリュームオフセットを必要に応じて設定することにより、該当リスナーにキャプチャされたサウンドがどのように各スピーカーから聞こえるかを指定することが可能で、更に制御力および柔軟性のある操作をすることができます。

これらの設定は、 AK::SoundEngine::SetListenerSpatialization() 関数を呼び出すことにより、各リスナーごとに変更可能です:

AkGameObjectID in_uListenerID, // Listener game object ID
bool in_bSpatialized, // Spatialization toggle (True : enable spatialization, False : disable spatialization)
AkChannelConfig in_channelConfig, // Channel configuration associated with volumes in_pVolumeOffsets. Ignored if in_pVolumeOffsets is NULL.
AK::SpeakerVolumes::VectorPtr in_pVolumeOffsets = NULL // Per-speaker volume offset, in dB. See AkSpeakerVolumes.h for how to manipulate this vector.
) = 0;

最初のパラメータは、リスナーのIDです。2つ目のパラメータは、該当リスナーに対する空間化を有効にするために True 、無効にするには False に設定される必要があります。最後のパラメータは、そのリスナーの各チャンネルのデシベル減衰を含む構造体への任意のポインタです。 in_bSpatializedFalse の場合、各チャンネルの音量が設定されます(デフォルトは 0 dBです)。 in_bSpatializedTrue の場合、デフォルトの3D spatializationで計算されたボリュームが、チャンネル毎に決めららた一定量だけ、オフセットされます。

ボリュームベクターはチャンネル構成 in_channelConfig にひも付けられています。 in_channelConfig が 5.1 を意味する場合には、ボリュームベクターは6の値である必要があります。AK::SpeakerVolumes::Vector ネームスペースで定義された機能を使用して、これを処理します。チャンネルの順番は、常に最後にあるLFEを除き、AkSpeakerConfig.hで定義されたチャンネルマスクビットに対応します。

2人のプレイヤーが分割画面を使用する例には、以下のコードを使用できます:

// すべてのエミッタのデフォルトリスナーとしてリスナー1と2を登録します。
// 代わりにAK::SoundEngine::SetListenersを使用して、どのエミッタからどのリスナーに放射するかを明確に選んで選択することができます。
AkGameObjectID listeners[2] = {1,2};
AK::SetDefaultListeners(listeners[0],2);
// Define speaker offsets using a 7.1 speaker setup (if platform supports it).
vVolumes[0] = 0.f; // Left
vVolumes[1] = -96.3f; // Right
vVolumes[2] = -6.f; // Center
vVolumes[3] = 0.f; // Rear left
vVolumes[4] = -96.3f; // Rear Right
vVolumes[5] = 0.f; // Side left
vVolumes[6] = -96.3f; // Side Right
vVolumes[7] = 0.f; // LFE
AK::SoundEngine::SetListenerSpatialization( listeners[0], false, cfg, vVolumes );
vVolumes[0] = -96.3f; // Left
vVolumes[1] = 0.f; // Right
vVolumes[2] = -6.f; // Center
vVolumes[3] = -96.3f; // Rear left
vVolumes[4] = 0.f; // Rear Right
vVolumes[5] = -96.3f; // Side left
vVolumes[6] = 0.f; // Side Right
vVolumes[7] = 0.f; // LFE
AK::SoundEngine::SetListenerSpatialization( listeners[1], false, cfg, vVolumes );

サウンドがルートされているバスに、そのユーザー定義のチャンネル構成につき、7.1と異なるチャンネル構成がされている場合には、サウンドに適用する前に、ベクターは内部的にダウンミックスされます。

通常の空間化に戻るには、以下を呼び出します:

// Enable regular spatialization on listeners 0 and 1

ボリュームパイプライン

次の図は、各スピーカーの最終音量を計算するために、各リスナーの各ソースで実行されるさまざまな操作を順番に示しています。

Wwise サウンドエンジンのボリュームパイプライン
参照
AKSOUNDENGINE_API AKRESULT SetDefaultListeners(const AkGameObjectID *in_pListenerObjs, AkUInt32 in_uNumListeners)
AkUInt32 uNumChannels
Number of channels.
Definition: AkSpeakerConfig.h:510
AkUInt64 AkGameObjectID
Game object ID
Definition: AkTypes.h:65
AKRESULT
Standard function call result.
Definition: AkTypes.h:122
AKSOUNDENGINE_API AKRESULT RegisterGameObj(AkGameObjectID in_gameObjectID)
AkForceInline AkUInt32 GetRequiredSize(AkUInt32 in_uNumChannelsIn, AkUInt32 in_uNumChannelsOut)
Compute size (in bytes) required for given channel configurations.
#define NULL
Definition: AkTypes.h:49
AkReal32 * VectorPtr
Volume vector. Access each element with the standard bracket [] operator.
Definition: AkSpeakerVolumes.h:49
#define AkAlloca(_size_)
Stack allocations.
Definition: AkPlatformFuncs.h:117
AKSOUNDENGINE_API AKRESULT SetListenerSpatialization(AkGameObjectID in_uListenerID, bool in_bSpatialized, AkChannelConfig in_channelConfig, AK::SpeakerVolumes::VectorPtr in_pVolumeOffsets=NULL)
#define AK_SPEAKER_SETUP_7_1
Definition: AkSpeakerConfig.h:200
AKSOUNDENGINE_API AKRESULT SetListeners(AkGameObjectID in_emitterGameObj, const AkGameObjectID *in_pListenerGameObjs, AkUInt32 in_uNumListeners)
AkForceInline void SetStandard(AkUInt32 in_uChannelMask)
Set channel config as a standard configuration specified with given channel mask.
Definition: AkSpeakerConfig.h:544
uint32_t AkUInt32
Unsigned 32-bit integer
Definition: AkTypes.h:86
AKSOUNDENGINE_API AKRESULT SetPosition(AkGameObjectID in_GameObjectID, const AkSoundPosition &in_Position)
Position and orientation of game objects.
Definition: AkTypes.h:323