バージョン
リスナーとは、ゲーム内のマイクの位置のことで、3D サウンドをスピーカーに割り当てて、3D 環境を模倣するためのものです。これは、ゲームオブジェクトの位置情報をリスナーの座標系にマッピングすることによって行われます。この座標系は、位置ベクター、前方向、上部方向ベクターにより定義されます。よって、リスナーの位置情報を常に最新に保っておかなければ、サウンドが誤ったスピーカーでレンダリングされてしまいます。
リスナーの位置を設定するには、AKSoundEngine::SetListenerPosition() 関数が使用されます。これは、リスナーの位置または方向ベクターのいずれかが変更されるたびに実行される必要があります。
AkListenerPosition listenerPosition; (... set the position and orientation members of listenerPosition here...) AK::SoundEngine::SetListenerPosition( listenerPosition );
AkListenerPosition 構造体は、ゲームの3D空間におけるリスナーの位置と方向を定義するベクターを保持しています:
struct AkListenerPosition { AkVector OrientationFront; // Orientation of the listener AkVector OrientationTop; // Top orientation of the listener AkVector Position; // Position of the listener };
|
Note: OrientationFront(前方向)ベクターは、リスナーの顔の向きを定義します。これは、リスナーの頭の傾斜を定義するOrientationTop(上部方向)ベクターに対して直角であるべきです。リスナーが人間であれば、OrientationFront ベクターがリスナーの鼻の向き(顔から外へ向かっている)となり、OrientationTop ベクターはそれに対して直角関係にあり、リスナーの目の間を通って顎とは逆方向を向きます。 |
X、Y および Z軸がどのようにWwise サウンドエンジンで定義されるかについては、X-Y-Z座標系 を参照してください。
方向ベクターは、オーディオが適切にレンダリングされるように定義されなければなりません。これらのベクターは、ゼロベクターではなく、単位ベクターであるべきで、そうでない場合は、単位ベクターに変換されます。また方向ベクターは直角を成すべきで、そうでない場合は、調整されます。
AK::SoundEngine::SetListenerPosition() は、2次的なオプショナルパラメータ in_ulIndex を持っています。これは、リスナーのインデックスを表し、0から7(0と7も含む)までの間の値でなければなりません。詳細は、複数リスナー を参照してください。
|
Note: リスナーの位置は、フレームごとに最大で1度更新されます。AKSoundEngine::SetListenerPosition() 関数への複数の呼び出しが行われても、AKSoundEngine::RenderAudio() の呼び出し時には、最後の値のみが考慮されます。 |
|
Tip: 例えば、左のスピーカーから聞こえるはずの音が右のスピーカーで聞こえるなど、予想外のサウンドレンダリングが発生している場合、AKSoundEngine::SetListenerPosition() 関数を介してサウンドエンジンに提供されるリスナーの位置情報を確認してください。その場合、既知の一定のリスナー位置を設定して、レンダリングが適切であるか確認し、X、Yおよび Z軸に発生している混同を排除することができます。この詳細については、X-Y-Z座標系 を参照してください。 |
ゲーム内での視野が1つのみのシングルプレイヤーゲームでは、リスナーは1つで十分です。しかしながら、同じシステム上で複数のプレイヤーがプレイできるゲームや、同時に複数の視点が表示される場合には、それぞれの視点にオーディオが適切にレンダリングされるよう、各視点ごとにリスナーが必要になります。
複数リスナーの実装に伴う主な難点は、サウンドソースの位置づけが、実際にプレイヤーが見ているものと調和しない場合があるということです。ほとんどのケースでは、複数プレイヤー向けの3D環境を再現するために単一のスピーカーセットのみを使用するゲームでこのような問題が発生します。
この問題を簡単に表現したのが以下の図です。リスナー0 には左のスピーカー、リスナー1 には右のスピーカーからソースが聞こえるように想定されているので、どのスピーカーでソースが再生されるべきかを知るのは非常に困難です。
異なるスピーカーで同じソースを聞く2つのリスナー
Wwiseサウンドエンジンは、0 から 7までのインデックスで識別されるリスナーを8つまでサポートします。以下のセクションでは、プログラマーが Wwise サウンドエンジンを使用して、これらのリスナーが期待通りの動作を実行するよう操作する方法を解説します。
|
Note: 複数リスナー機能は、3D ゲーム定義モードのサウンドオブジェクトセットに影響を与えます。2D または 3D ユーザー定義モードのオブジェクトセットは、ゲーム環境におけるソースとリスナーの位置とは関係なく様々なスピーカーに配置されるので、複数リスナー機能の影響を受けません。 |
|
Note: 複数リスナーに関連する操作は、SDK を介したゲームプログラマーによる実装によってのみ可能です。 Wwise オーサリングアプリケーションには、複数リスナーのためにソースのゲーム内ポジショニングを管理する特別なオプションはありません。 |
デフォルトでは、すべてのソースがリスナー 0 にのみアサインされていますが、開発者によって8つのリスナーのいずれにでもアサインすることが可能です。ソースがアクティブになっている各リスナーに対して相対的にソースごとの距離とコーン減衰が個別計算されます。
複数のリスナーがソースをキャプチャすると、Wwise は各リスナーの全チャンネルのボリュームをチェックし、それぞれのチャンネルの最大ボリュームを保ちます。
以下は、同じソースをキャプチャする2つのゲームリスナーの例です。
リスナー 0 (dB単位のボリューム) |
リスナー 1 (dB単位のボリューム) |
ソースの 最終ボリューム |
|
フロントレフト | -6 | -56 | -6 |
フロントライト | -18 | -15 | -15 |
センター | -54 | -37 | -37 |
リアレフト | -7 | -48 | -7 |
リアライト | -54 | -9 | -9 |
LFE | -96.3 | -96.3 | -96.3 |
各ソースに適用する最終のローパスフィルターをサウンドエンジンが計算する方法は以下のとおりです:
次の表で説明されている例では、リスナー0 の値は max( 10, 40 ) = 40、リスナー1 の値は max( 50, 10 ) = 50 です。2つのうち最も低いのは40で、これがオブジェクトの値5に追加され、最終的な値が45になります:
リスナー 0 | リスナー 1 | オブジェクト |
ソースの 最終 LPF |
|||
コーン LPF | 半径 LPF | コーン LPF | 半径 LPF | |||
LPF | 10 | 40 | 50 | 10 | 5 | 45 |
デフォルトでは、ゲーム内でインスタンス化されている各ゲームオブジェクトは、リスナー0 にのみアサインされています。デフォルトでは、ゲーム内でインスタンス化されている各ゲームオブジェクトは、リスナー0 にのみアサインされていますが、ゲーム開発者は、これらのゲームオブジェクトのリスナーへのアサインやアサイン解除を動的に実行することができます。
例えば、通常ならリスナーが聞き取る近距離にあるソースを、リスナーが聞き取らないようにしたほうが良いような状況があります。
L1 にソースが聞こえてはならない例
この図では、壁のオクルージョンにより、L1 がソースを聞き取れないことがわかります。このシナリオでは、開発者が S1 を再生するゲームオブジェクトの L1 へのアサインを一時的に解除することができます。実際にオクルージョンを使用したい場合は、オブストラクションとオクルージョンの設定 を参照してください。
AK::SoundEngine::SetActiveListeners() 関数によって、特定のゲームオブジェクトに対して、どのリスナーをアクティブにする必要があるかを指定することができます:
virtual AKRESULT AK::SoundEngine::SetActiveListeners( AkGameObjectID in_GameObjectID, // Game object identifier AkUInt32 in_uListenerMask // Bitmask representing active listeners (LSB = Listener 0, set to 1 means active) ) = 0;
特定のゲームオブジェクトに対して、8つのリスナーのうちのいずれをアクティブにするか指定するには、2番目のパラメータとして渡された値の対応ビットを1(アクティブ)または0(非アクティブ)に設定します。最下位ビット(LSB)がリスナー0を表します:
// Activate only Listener 0 on this Game Object AK::SoundEngine::SetActiveListeners( gameObject1, 0x00000001 ); // Activate Listeners 1, 2 and 3 on this Game Object (Listeners 0 and 4 to 7 // are deactivated for this Game Object) AK::SoundEngine::SetActiveListeners( gameObject2, 0x0000000E );
空間化とは、 3D ゲーム定義のサウンドを、リスナーに対するサウンドの位置に基づいて、複数のスピーカーに位置づけることです。
しかし、2人のプレイヤーによって分割画面でゲームがプレイされる場合、各リスナーに対するサウンドの位置に基づいた、通常通りのスピーカーへのサウンドポジショニングを完全に回避して、リスナー0(1人目のプレイヤー)を左のスピーカー、リスナー1(2人目のプレイヤー)を右のスピーカーで聞こえるようにしたいかもしれません。
ゲームプログラマーは、Wwiseを介して特定のリスナー向けの空間化を無効にし、各チャンネルに対するカスタムのボリュームオフセットを必要に応じて設定することにより、該当リスナーにキャプチャされたサウンドがどのように各スピーカーから聞こえるかを指定することが可能で、更に制御力および柔軟性のある操作をすることができます。
これらの設定は、AKSoundEngine::SetListenerSpatialization() 関数を呼び出すことにより、各リスナーごとに変更可能です:
virtual AKRESULT AK::SoundEngine::SetListenerSpatialization( AkUInt32 in_uIndex, // Listener index (0: first listener, 7: 8th listener) 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;
最初のパラメータは、リスナーのインデックス(0 から 7)です。2つ目のパラメータは、該当リスナーに対する空間化を有効にするために True、無効にするには
False
に設定される必要があります。最後のパラメータは、そのリスナーの各チャンネルのデシベル減衰を含む構造体への任意のポインタです。in_bSpatialized
が Trueの場合、これは
NULL でなければなりません。in_bSpatialized
が False
の場合、デフォルトでは 0dB である各チャンネルのボリュームオフセットが変更されます。
ボリュームベクターはチャンネル構成 in_channelConfig
にひも付けられています。 in_channelConfig
が 5.1 を意味する場合には、ボリュームベクターは6の値である必要があります。AKSpeakerVolumes::Vector ネームスペースで定義された機能を使用して、これを処理します。チャンネルの順番は、常に最後にあるLFEを除き、AkSpeakerConfig.hで定義されたチャンネルマスクビットに対応します。
2人のプレイヤーが分割画面を使用する例には、以下のコードを使用できます:
// Define speaker offsets using a 7.1 speaker setup (if platform supports it). AkChannelConfig cfg; cfg.SetStandard( AK_SPEAKER_SETUP_7_1 ); AkUInt32 uVectorSize = AK::SpeakerVolumes::Vector::GetRequiredSize( cfg.uNumChannels ); AK::SpeakerVolumes::VectorPtr vVolumes = (AK::SpeakerVolumes::VectorPtr)AkAlloca( uVectorSize ); 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( 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( 1, false, cfg, vVolumes );
サウンドがルートされているバスに、そのユーザー定義のチャンネル構成につき、7.1と異なるチャンネル構成がされている場合には、サウンドに適用する前に、ベクターは内部的にダウンミックスされます。
通常の空間化に戻るには、以下を呼び出します:
// Enable regular spatialization on listeners 0 and 1 AK::SoundEngine::SetListenerSpatialization( 0, true ); AK::SoundEngine::SetListenerSpatialization( 1, true );
次の図は、各スピーカーの最終的なボリュームを計算するために、各リスナー向けの全てのソースに対する様々な操作を、実行される順に示したものです:
Wwise サウンドエンジンのボリュームパイプライン