ゲームでドップラー効果をシミュレートするにはどうすればよいですか?


14

ゲーム(カーレースゲーム)でドップラー効果をシミュレートしようとしています。エフェクトをシミュレートする特定のサウンドライブラリを使用していません。データをミックスするコールバック関数しかありません。

ミキサー機能でサンプルの周波数を変更する方法はすでにわかっています。

私が知らないのは、プレイヤーとエミッターの位置と速度に応じて周波数がどれだけ変化するかです。

ここに私がゲームに持っているものがあります:

//player 
vec3 p.pos; 
vec3 p.vel;

//emitter 
vec3 e.pos;
vec3 e.vel;

1)ウィキペディアによると、放射周波数と観測周波数の関係は次のように与えられます。

float f = (c + vr) / (c + vs) * fo

ここで、Cは定数、媒体の速度(典型的には大きい数)であり、 vrは媒体に対するソースとレシーバーの速度です。

だから私は推測する:

float vr = p.vel.length; //player speed 
float vs = e.vel.length; //emitter speed

しかし、私はその間違ったが、それは例えばのために、周波数の変化をもたらす文句を言わないと思う:場合vr = 0(プレイヤーいけない移動)とエミッタと、一定の速度を持っているし、vrそしてvs文句を言わないの変更(彼らが必要しばらく)。

多分、エミッタの速度に対して相対的にプレーヤーの速度を計算する必要がありますか?

このような :

relative_speed = distance(p.pos + p.vel, e.pos + e.vel) -
distance(p.pos, e.pos);

その後、どのようにvrしてvs養うべきか?


2)ウィキペディアは、車両がオブザーバーを通過する車両の効果をシミュレートする別の式も提供します。

vr = vs * cos(theta);

//theta is angle between observer and emitter
//theta = atan2(e.pos.y-p.pos.y, e.pos.x-p.pos.x); ?

ただし、この式は、レシーバーが動かないことを想定していますが、ここではそうではありません。プレーヤーとエミッターが同じ速度(またはわずかな差)で移動する場合、ドップラー効果はありません。また、この関数は1つのケースに固有です。最終的な式は状況に関係なく同じであると仮定します。


編集:私はSkimFluxの投稿を使用して正しい式を見つけようとしています:

vr,r = vr.vel * cos(shortest_angle_between ( vr.vel , vs.pos - vr.pos)); 
vs,r = vs.vel * cos(shortest_angle_between ( vs.vel , vr.pos - vs.pos)); 

//is there a easier/faster way to find them out ? 
//note: vr.vel and vs.vel are vectors, the green and red arrows on SkimFlux picture. 

EDIT2:

興味のある方のために、ここに最終的な公式があります:

vec2 dist = vs.pos - vr.pos;

vr,r = dotproduct(vr.vel, dist) / length(dist)
vs,r = dotproduct(vs.vel, dist) / length(dist)

注:ここで説明するベクトル投影を使用します

投影式

次いで、vr,s及びvs,r第Wikipediaの式に注入されるべきです。

ここに画像の説明を入力してください

私はそれをテストし、うまく機能し、素晴らしい結果を提供しました。


3
ソースの実際の動きをレシーバーに対する相対的な動きに置き換えることにより、レシーバーが動いていないと仮定する式を調整できます。
yoozer8

回答:


9

1)両方のオブジェクトが同じ線上で動いていると仮定します-(これはリンクしたウィキペディアのページで説明されています)あなたの結論は正しいです。この状況では、一定の速度で、周波数シフトは一定です。周波数シフトを変更するにVsは、一定であるがSR軸と同一直線上にない状況では、相対速度を変更する必要があるため、式2)が必要です。

ただし、式2)は誤解を招く可能性があります。つまり、ソース速度の動径/相対成分Vrと読み替えてくださいVs,r

ドップラー効果は速度のみに依存し、SR軸を見つけるための位置のみが必要であることに注意してください。

編集:これは、あなたが使用する必要がある、あなたは速度を把握助けるべきであるVs,rVr,r式1で数量:

ドップラーシフトの相対速度


回答(および写真)に感謝します。これですべてが明確になったので、式1と2を組み合わせる必要があります。説明したように、オブジェクトが同じ行にない場合、formula2は便利です。最後の部分はvr、rおよびvs、rを見つけることです。vr、r = vr.vel * cos(shortest_angle_between(vr.vel、vs.pos-vr.pos)); vs、r = vs.vel * cos(shortest_angle_between(vs.vel、vr.pos-vs.pos)); //それらを見つけるより簡単/高速な方法はありますか?//vr.velとvs.velはベクトルであり、SkimFlux画像の緑と赤の矢印に注意してください。
ティグロウ

最初の投稿を編集し、正しい形式の数式を追加しました。それらを確認できますか?(初めてgamedev stackexchangeを使用します。返信で行リターンを保持しないことを知りませんでした。そのコメントは5分後にロックされます...)
tigrou

@ user1083855はい、それらは正しく見えます。より簡単/高速にするための1つの方法は、Jimの提案に従い、式2)を使用し、両方の相対運動を行うことです。実際のドップラー効果は音媒体(空気)に対する両方のエンティティの速度に依存するため、実際に同じだとは思いませんが、ゲームの状況ではおそらく十分に近く、高価なcos操作を節約できます。
SkimFlux

まあ、実際に私はvr、r vs、rを見つけるはるかに簡単な方法を見つけました:en.wikipedia.org/wiki/Vector_projection
tigrou

0

XACTには、ドップラーピッチスカラー変数を指定する必要があります。つまり、相対速度です。1.0は同じ速度ですが、<1.0はより遅く、> 1.0はより高速です。

画面の位置とキューの間で音が計算されるこのC#に転送したコードをありがとう。正確に動作します

soundElements.ForEach(e =>
            {
                var cuePosition = new Vector3(e.PhysicPosition, 0);
                var distance = cuePosition - ScreenCenter;
                var distanceLength = distance.Length();
                e.Cue.SetVariable("Distance", distanceLength);
                var dopplerPitchScalar = 1.0f;
                if (e.AssociatedBody != null)
                {
                    ///gamedev/23583/how-do-i-simulate-a-doppler-effect-in-a-game
                    var screenVelocity = Vector3.Dot(ScreenVelocity, distance) / distanceLength;
                    var cueVelocity = Vector3.Dot(new Vector3(e.AssociatedBody.LinearVelocity, 0), distance) / distanceLength;
                    var relativeVelocity = screenVelocity - cueVelocity;
                    dopplerPitchScalar = (1f + relativeVelocity / SoundEffect.SpeedOfSound) / (1f - relativeVelocity / SoundEffect.SpeedOfSound);
                    //Console.WriteLine($"C: {ScreenCenter}, V: {ScreenVelocity}, D: {dopplerPitchScalar}");
                }
                e.Cue.SetVariable("DopplerPitchScalar", dopplerPitchScalar);
            });

ところで

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.