Bir oyunda doppler efektini nasıl simüle edebilirim?


14

Bir oyunda (araba yarışı oyunu) doppler etkisini simüle etmeye çalışıyorum. Etkisini simüle eden belirli bir ses kütüphanesi kullanmıyorum, sadece verileri karıştırdığım bir geri arama işlevim var.

Mikser fonksiyonunda bir numunenin frekansının nasıl değiştirileceğini zaten anladım.

Bilmediğim, frekansın ne kadar oynatıcına ve yayıcı konumuna ve hızına bağlı olarak değişmesi gerektiğidir.

İşte oyunda ne var:

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

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

1) Vikipedi'ye göre , yayılan frekans ile gözlemlenen frekans arasındaki ilişki şu şekilde verilir:

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

burada C , bir sabit, orta hız (tipik olarak büyük bir sayı) vs ve vr orta görece kaynak ve alıcı hızları.

yani sanırım:

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

ama bunun yanlış olduğunu düşünüyorum, örneğin herhangi bir frekans değişikliği üretmeyecek, örneğin: eğer vr = 0(oyuncu hareket etmiyorsa) ve yayıcı sabit hıza sahipse, o zaman vrve vsdeğişmeyecekler (gerekirken).

belki oyuncunun hızını yayıcının hızına göre hesaplamalıyım?

bunun gibi :

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

o zaman nasıl vrve nasıl vsbeslenmelidir?


2) wikipedia ayrıca aracın gözlemci tarafından geçtiği bir aracın etkisini simüle etmek için başka bir formül verir:

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); ?

Bununla birlikte, bu formül, alıcının hareket etmediğini varsayar; bu durum böyle değildir. oynatıcı ve verici aynı hızda (veya küçük farkta) hareket ederse, doppler etkisi olmamalıdır. Bu fonksiyon da bir vakaya özgüdür, son formülün durumun aynı olmaması gerektiğini varsayalım.


EDIT: doğru formül bulmaya çalışıyorum, SkimFlux yazı kullanarak:

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:

İlgilenenler için işte son formül:

vec2 dist = vs.pos - vr.pos;

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

NOT: burada açıklanan vektör projeksiyonu kullanır :

projeksiyon formülü

o zaman vr,sve vs,rilk wikipedia formülüne enjekte edilmelidir:

resim açıklamasını buraya girin

Test ettim ve harika sonuçlar vererek başarılı bir şekilde çalışıyor.


3
Kaynağın gerçek hareketini, alıcıya göre hareketiyle değiştirerek alıcının hareket etmediğini varsayan formülü uyarlayabilirsiniz.
yoozer8

Yanıtlar:


9

1) Her iki nesnenin de aynı çizgi üzerinde hareket ettiğini varsayar (bu, bağladığınız wikipedia sayfasında açıklanır) sonucunuz doğrudur, bu durumda sabit hızlarda frekans kayması sabittir. Frekans kaymasının değişmesi için, göreceli hızların, dolayısıyla formül 2) değişmesi, Vssabit fakat SR ekseni ile doğrusal olmayan durum için değişmesi gerekir .

Formül 2) yanıltıcıdır: kaynak hızının radyal / bağıl bileşeni Vrolarak okunmalıdır Vs,r.

Doppler efektinin sadece hızlara bağlı olduğunu, sadece SR eksenini bulmak için konumlara ihtiyacınız olduğunu lütfen unutmayın.

Düzenleme : Bu, hızları anlamanıza yardımcı olacaktır , formül 1 ile Vs,rve Vr,rmiktarlarını kullanmanız gerekir :

Doppler kayması için bağıl hızlar


tamam Cevabınız (ve resminiz) için teşekkür ederim, çok yardımcı olur. şimdi her şey açık, formül 1 ve 2'yi bir araya getirmeliyim. açıkladığınız gibi, nesneler aynı çizgide olmadığında formula2 irade yararlı olacaktır. son bölüm vr, r ve vs, r'yi bulmaktır. vr, r = vr.vel * cos (en kısa_angle_between (vr.vel, vs.pos - vr.pos)); vs, r = vs.vel * cos (en kısa_angle_between (vs.vel, vr.pos - vs.pos)); // bunları bulmanın daha kolay / hızlı bir yolu var mı? // vr.vel ve vs.vel vektörler, SkimFlux resmindeki yeşil ve kırmızı oklar.
tigrou

İlk gönderiyi düzenledim ve doğru biçimlendirmeyle formül ekledim. Onları kontrol edebilir misin? (Ben ilk kez gamedev stackexchange kullanın. satır cevapları tutmak olmaz alışkanlık bilmiyordum ve bu yorum 5 dakika sonra kilitli ...)
tigrou

@ user1083855 Evet, bunlar doğru görünüyor. Daha basit / daha hızlı yapmanın bir yolu, Jim'in önerisini takip etmek ve formül 2 )'yi her ikisi arasındaki göreceli hareketle kullanmak olacaktır. Gerçekten aynı olduğunu düşünmüyorum çünkü gerçek Doppler etkisi her iki objenin ses ortamına (havaya) göre hızlarına bağlı, ancak bir oyun durumunda muhtemelen yeterince yakın olacak ve pahalı bir işletimden tasarruf edeceksiniz.
SkimFlux

aslında, vr, r vs, r bulmak için çok daha kolay bir yol buldum: en.wikipedia.org/wiki/Vector_projection
tigrou

0

XACT için, doppler adım skaler değişkeni belirtilmelidir, yani nispi hız, burada 1.0 aynı hızdır, ancak <1.0 daha yavaş ve> 1.0 daha hızlıdır

Ekran konumu ve bir işaret arasında bir ses hesaplandığı bu C # parçasına aktardığım kod için teşekkür ederim. Hassas çalışır

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);
            });

Btw.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.