मैं एक गेम में डॉपलर प्रभाव का अनुकरण कैसे करूं?


14

मैं एक खेल (एक कार रेसिंग खेल) में डॉपलर प्रभाव का अनुकरण करने की कोशिश कर रहा हूं। मैं एक विशिष्ट ध्वनि पुस्तकालय का उपयोग नहीं कर रहा हूं जो प्रभाव का अनुकरण करता है, मेरे पास केवल कॉलबैक फ़ंक्शन है जहां मैं डेटा मिलाता हूं।

मुझे पहले से ही पता चल गया था कि मिक्सर फ़ंक्शन में एक नमूना की आवृत्ति कैसे बदलनी है।

मुझे नहीं पता कि खिलाड़ी और उत्सर्जक स्थिति और वेग के आधार पर आवृत्ति कितनी होनी चाहिए।

यहाँ मैं क्या खेल में है:

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

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

1) विकिपीडिया के अनुसार , उत्सर्जित आवृत्ति और देखे गए आवृत्ति के बीच का संबंध निम्न द्वारा दिया गया है:

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

जहाँ c एक स्थिर है, माध्यम में वेग (आमतौर पर एक बड़ी संख्या) बनाम और वीआर स्रोत और रिसीवर के माध्यम से सापेक्ष वेग हैं।

तो मुझे लगता है :

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

लेकिन मुझे लगता है कि इसकी गलत है, यह नहीं होते उदाहरण के लिए आवृत्ति में कोई बदलाव, उत्पादन: अगर vr = 0(खिलाड़ी न चाल) और emitter स्थिर गति है, तो है 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); ?

हालाँकि, इस सूत्र ने माना कि रिसीवर न ले जाएँ, जो यहाँ नहीं है। यदि खिलाड़ी और एमिटर समान गति (या छोटे अंतर) पर चलते हैं, तो कोई डॉपलर प्रभाव नहीं होना चाहिए। यह फ़ंक्शन एक मामले के लिए भी विशिष्ट है, मुझे लगता है कि अंतिम फॉर्मूला वही होना चाहिए जो किसी भी स्थिति में न हो।


संपादित करें: मैं स्किमफ्लक्स पोस्ट का उपयोग करके सही सूत्र खोजने की कोशिश कर रहा हूं:

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एसआर अक्ष के साथ स्थिर नहीं है, लेकिन कॉलिनियर नहीं है।

फॉर्मूला 2) हालांकि भ्रामक है: Vrको Vs,rस्रोत वेग के रेडियल / सापेक्ष घटक के रूप में पढ़ा जाना चाहिए ।

कृपया ध्यान दें कि डॉपलर प्रभाव केवल वेग पर निर्भर करता है, आपको केवल एसआर अक्ष को खोजने के लिए पदों की आवश्यकता होती है।

संपादित करें : इससे आपको वेगों का पता लगाने में मदद मिलेगी, आपको सूत्र 1 के साथ Vs,rऔर Vr,rमात्राओं का उपयोग करने की आवश्यकता है :

डॉपलर शिफ्ट के लिए सापेक्ष वेग


ठीक है आपके उत्तर के लिए धन्यवाद (और चित्र), यह बहुत मदद करता है। अब सब कुछ स्पष्ट है, मुझे फॉर्मूला 1 और 2 को एक साथ जोड़ना चाहिए। जैसा कि आपने बताया, सूत्र 2 तब उपयोगी होता है जब ऑब्जेक्ट एक ही पंक्ति में नहीं होते हैं। अंतिम भाग vr, r और vs, r का पता लगाना है। vr, r = vr.vel * cos (shortest_angle_between (vr.vel, Dispos - vr.pos)); बनाम, आर = बनामवेल * कॉस (शॉर्टएस्ट_एंगल_बेटी (बनामवेल, वीआरओपोस - डिस्पोज़)); // क्या उनका पता लगाने का एक आसान / तेज तरीका है? // नोट vr.vel और विवेल वैक्टर हैं, स्किमफ्लक्स तस्वीर पर हरे और लाल तीर।
tigrou

मैंने सही फॉर्मेटिंग के साथ पहली पोस्ट और अतिरिक्त सूत्र को संपादित किया। क्या आप उन्हें जांच सकते हैं? (पहली बार मैं gamedev स्टेक्सएक्सचेंज का उपयोग करता हूं। मुझे नहीं पता था कि यह उत्तर में लाइन रिटर्न बनाए रखेगा, और यह टिप्पणी 5 मिनट के बाद बंद हो जाएगी ...)
टिग्रो

@ user1083855 हां, वे सही लग रहे हैं। इसे सरल / तेज़ बनाने का एक तरीका यह होगा कि जिम के सुझाव का पालन करें और सूत्र 2 का उपयोग करें) दोनों के बीच सापेक्ष आंदोलन के साथ। मुझे नहीं लगता कि यह वास्तव में एक ही है क्योंकि वास्तविक डॉपलर प्रभाव ध्वनि माध्यम (वायु) के सापेक्ष दोनों संस्थाओं के वेग पर निर्भर करता है, लेकिन एक गेम की स्थिति में यह संभवतः काफी करीब होगा और आपको एक महंगा कॉस ऑपरेशन बचाएगा।
स्किमफ्लक्स

ठीक है, वास्तव में मुझे 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 Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.