Як я імітую ефект доплера в грі?


14

Я намагаюся імітувати ефект допплера в грі (гра в гоночний автомобіль). Я не використовую певну звукову бібліотеку, яка імітує ефект, у мене є лише функція зворотного дзвінка, де я змішую дані.

Я вже зрозумів, як змінити частоту зразка у функції змішувача.

Я не знаю, наскільки частота повинна змінюватися залежно від позиції гравця та випромінювача.

Ось що у мене в грі:

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

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

1) Згідно з Вікіпедією , співвідношення між випромінюваною частотою та спостережуваною частотою задається:

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

де c - константа, швидкість у середовищі (зазвичай велика кількість) vs і 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) wikipedia також дає іншу формулу для імітації ефекту транспортного засобу, який транспортний засіб проходить повз спостерігача:

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

однак ця формула припускає, що приймач не рухається, що тут не так. якщо гравець і емітер рухаються з однаковою швидкістю (або невеликою різницею), ефекту допплера не повинно бути. ця функція специфічна і для одного випадку, я вважаю, що остаточна формула повинна бути однаковою, не залежно від ситуації.


EDIT: Я намагаюся знайти правильну формулу, використовуючи допис 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слід вводити у формулу першої вікіпедії:

введіть тут опис зображення

Я перевірив це, і він працює успішно, даючи чудові результати.


3
Ви можете адаптувати формулу, яка передбачає, що приймач не рухається, замінивши фактичний рух джерела на його рух відносно приймача.
yoozer8

Відповіді:


9

1) Припускаємо, що обидва об'єкти рухаються на одній лінії - (це пояснено на сторінці вікіпедії, яку ви пов’язали) ваш висновок правильний, в цій ситуації з постійними швидкостями зсув частоти є постійним. Для зміни зсуву частоти відносні швидкості потрібно змінювати, отже, формула 2), для ситуації, коли вона Vsє постійною, але не співпадає з віссю SR.

Формула 2) оманлива, однак: її Vrслід читати як Vs,rрадіальну / відносну складову швидкості джерела.

Зверніть увагу, що ефект Доплера залежить лише від швидкостей, потрібні лише положення, щоб знайти вісь SR.

Редагувати : це повинно допомогти вам розібратися у швидкостях, вам потрібно використовувати формули Vs,rта Vr,rвеличини з формулою 1:

Відносні швидкості для доплерівського зсуву


ок, дякую за вашу відповідь (і малюнок), це дуже допомагає. тепер усе зрозуміло, я повинен поєднувати формули 1 і 2 разом. як ви пояснили, formula2 буде корисним, коли об'єкти не знаходяться в одному рядку. остання частина полягає у з'ясуванні vr, r та vs, r. vr, r = vr.vel * cos (найкоротший_гонок_між (vr.vel, vs.pos - vr.pos)); vs, r = vs.vel * cos (shorttest_angle_bet between (vs.velvel, vr.pos - vs.pospos)); // чи є простіший / швидший спосіб їх виявити? // note vr.vel і vs.vel - вектори, зелена та червона стрілки на малюнку SkimFlux.
тигру

Я відредагував першу публікацію і додав формулу з правильним форматуванням. Ви можете їх перевірити? (вперше я використовую gamedev stackexchange. Я не знаю, що це не буде тримати відповідь у відповідь, і цей коментар блокується через 5 хв ...)
tigrou

@ user1083855 Так, це виглядає правильно. Одним із способів зробити його простішим / швидшим було б дотримуватися пропозиції Джима та використовувати формулу 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);
            });

Btw.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.