दूरी समारोह का अनुकूलन कैसे करें?


23

एक यथोचित सरल आरटीएस जैसे खेल को विकसित करते हुए, मैंने देखा कि मेरी दूरी की गणना प्रदर्शन में प्रभाव पैदा कर रही है।

हर समय, यह जानने के लिए दूरस्थ जांच होती है कि क्या कोई इकाई अपने लक्ष्य की सीमा में है, यदि प्रक्षेप्य अपने लक्ष्य पर पहुंच गया है, यदि खिलाड़ी पिकअप, सामान्य टक्कर, आदि पर चला गया है, तो सूची चल रही है, और उसके लिए जाँच की जा रही है। दो बिंदुओं के बीच की दूरी का बहुत उपयोग किया जाता है।

मेरा प्रश्न ठीक उसी के बारे में है। मैं जानना चाहता हूं कि सामान्य स्क्वैरर्ट (x * x + y * y) दृष्टिकोण के अलावा दूरियों की जाँच के लिए गेम डेवलपर्स के पास क्या विकल्प हैं, जो कि हम प्रति फ्रेम हजारों बार प्रदर्शन कर रहे हैं, तो काफी समय लगता है।

मैं इंगित करना चाहता हूं कि मैं मैनहट्टन दूरी और वर्ग दूरी की तुलना (वर्गर्ट अड़चन को छोड़कर) से अवगत हूं। और कुछ?



यदि आपके पास ऐसी वस्तुएं हैं, जिन्हें आप इमारतों की तरह स्थानांतरित करने की उम्मीद नहीं करते हैं, उदाहरण के लिए, यह दूरी समारोह के 2 डी टेलर श्रृंखला लेने के लिए इसके लायक हो सकता है, इसे वर्ग अवधि में छोटा कर दें, और फिर परिणामी फ़ंक्शन को स्टोर के रूप में संग्रहीत करें उस विशेष इमारत से दूरी समारोह। यह ग्रंट के कुछ काम को आरंभीकरण के लिए स्थानांतरित कर देगा और चीजों को थोड़ा बढ़ा सकता है।
अलेक्जेंडर ग्रुबर

जवाबों:


26

टी एल; डॉ; आपकी समस्या दूरस्थ कार्य करने में नहीं है। आपकी समस्या कई बार दूरी कार्य कर रही है। दूसरे शब्दों में आपको गणितीय के बजाय एक एल्गोरिथम अनुकूलन की आवश्यकता है।

[संपादित करें] मैं अपने उत्तर के पहले खंड को हटा रहा हूं, क्योंकि लोग इससे नफरत कर रहे हैं। प्रश्न शीर्षक संपादन से पहले वैकल्पिक दूरी के कार्यों के लिए पूछ रहा था।

आप एक दूरी फ़ंक्शन का उपयोग कर रहे हैं जहां आप हर समय वर्गमूल की गणना कर रहे हैं। फिर भी, आप बस वर्गमूल का उपयोग किए बिना इसे प्रतिस्थापित कर सकते हैं और इसके बजाय दूरी की गणना कर सकते हैं। यह आपको बहुत सारे कीमती चक्रों को बचाएगा।

दूरी ^ 2 = x * x + y * y;

यह वास्तव में एक आम चाल है। लेकिन आपको अपने हिसाब से तालमेल बिठाने की जरूरत है। वास्तविक दूरी की गणना करने से पहले इसे प्रारंभिक जांच के रूप में भी इस्तेमाल किया जा सकता है। इसलिए उदाहरण के लिए एक चौराहे के परीक्षण के लिए दो बिंदुओं / क्षेत्रों के बीच वास्तविक दूरी की गणना करने के बजाय हम दूरी वर्ग की गणना कर सकते हैं और त्रिज्या के बजाय त्रिज्या वर्ग की तुलना कर सकते हैं।

@ Byte56 के बाद, संपादित करें, यह इंगित किया कि मैंने प्रश्न नहीं पढ़ा था, और आपको चुकता दूरी अनुकूलन के बारे में पता था।

आपके मामले में, दुर्भाग्य से हम कंप्यूटर ग्राफिक्स में लगभग विशेष रूप से यूक्लिडियन स्पेस के साथ काम कर रहे हैं , और दूरी को यूक्लिडियन स्पेस में बिल्कुल परिभाषित किया Sqrt of Vector dot itselfगया है।

दूरी चुकता वह सबसे अच्छा सन्निकटन है जिसे आप प्राप्त करने जा रहे हैं (प्रदर्शन के मामले में), मैं 2 गुणा, एक जोड़, और एक असाइनमेंट धड़कता हुआ कुछ भी नहीं देख सकता।

तो आप कहते हैं कि मैं दूरी समारोह का अनुकूलन नहीं कर सकता हूं मुझे क्या करना चाहिए?

आपकी समस्या दूरस्थ कार्य करने में नहीं है। आपकी समस्या कई बार दूरी कार्य कर रही है। दूसरे शब्दों में आपको गणितीय के बजाय एक एल्गोरिथम अनुकूलन की आवश्यकता है।

मुद्दा यह है कि दृश्य में प्रत्येक वस्तु के साथ खिलाड़ी चौराहे की जांच करने के बजाय, प्रत्येक फ्रेम। आप आसानी से अपने लाभ के लिए स्थानिक सुसंगतता का उपयोग कर सकते हैं, और केवल उन वस्तुओं की जांच कर सकते हैं जो खिलाड़ी के पास हैं (जो हिट / इंटरसेक्ट होने की सबसे अधिक संभावना है)।

यह आसानी से एक स्थानिक विभाजन डेटा संरचना में उन स्थानिक जानकारी को संग्रहीत करके आसानी से किया जा सकता है । एक साधारण खेल के लिए मैं एक ग्रिड का सुझाव दूंगा क्योंकि यह मूल रूप से लागू करना आसान है और गतिशील दृश्य को अच्छी तरह से फिट बैठता है।

प्रत्येक सेल / बॉक्स में ऑब्जेक्ट की एक सूची होती है जो ग्रिड के बाउंडिंग बॉक्स को संलग्न करती है। और उन कोशिकाओं में खिलाड़ी की स्थिति को ट्रैक करना आसान है। और दूरी की गणना के लिए, आप केवल दृश्य में सब कुछ के बजाय एक ही या पड़ोसी कोशिकाओं के अंदर उन वस्तुओं के साथ खिलाड़ी की दूरी की जांच करते हैं।

एक अधिक जटिल दृष्टिकोण बीएसपी या ऑक्ट्रेसेस का उपयोग करना है।


2
मेरा मानना ​​है कि प्रश्न का अंतिम वाक्य कहता है कि ओपी अन्य विकल्पों की तलाश कर रहा है (वे चुकता दूरी का उपयोग करने के बारे में जानते हैं)।
MichaelHouse

@ Byte56 हाँ आप सही हैं, मैंने ऐसा नहीं पढ़ा।
concept3d

आप वैसे भी जवाब के लिए धन्यवाद। क्या आप यह कहते हुए एक वाक्य जोड़ेंगे कि भले ही वह तरीका हमें एक यूक्लिडियन दूरी न दे, यह तुलना में बहुत सटीक है? मुझे लगता है कि खोज इंजन से यहां आने वाले किसी व्यक्ति के लिए कुछ जोड़ देगा।
ग्रिम्शॉ

@Grimshaw मैंने मूल समस्या से निपटने के लिए उत्तर संपादित किया।
concept3d

@ बाइट 56 इशारा करने के लिए धन्यवाद। मैंने उत्तर संपादित किया।
concept3d

29

यदि आपको किसी ऐसी चीज की आवश्यकता है जो किसी भी दूरी पर (विपरीत distance^2) में रैखिक रहती है और फिर भी अस्पष्ट रूप से गोलाकार दिखाई देती है (स्क्वरिश चेबीशेव और हीरे की तरह मैनहट्टन की दूरी के विपरीत), तो आप एक अष्टकोणीय आकार के दूरी अनुमान प्राप्त करने के लिए बाद की दो तकनीकों को औसत कर सकते हैं:

dx = abs(x1 - x0)
dy = abs(y1 - y0)

dist = 0.5 * (dx + dy + max(dx, dy))

यहाँ एक विज़ुअलाइज़ेशन (समोच्च प्लॉट) फ़ंक्शन का है, वुल्फराम अल्फा के लिए धन्यवाद :

समोच्च साजिश

और यहां इसकी त्रुटि फ़ंक्शन की एक साजिश है जब यूक्लिडियन दूरी (रेडियन, पहले चतुर्थांश केवल) की तुलना में:

त्रुटि प्लॉट

जैसा कि आप देख सकते हैं, त्रुटि कुल्हाड़ियों पर 0% से लेकर लोब में लगभग + 12% तक है। गुणांक को थोड़ा संशोधित करके हम इसे +/- 4% तक प्राप्त कर सकते हैं:

dist = 0.4 * (dx + dy) + 0.56 * max(dx, dy)

यहाँ छवि विवरण दर्ज करें

अद्यतन करें

उपरोक्त गुणांक का उपयोग करते हुए, अधिकतम त्रुटि +/- 4% के भीतर होगी, लेकिन औसत त्रुटि अभी भी + 1.3% होगी। शून्य औसत त्रुटि के लिए अनुकूलित, आप उपयोग कर सकते हैं:

dist = 0.394 * (dx + dy) + 0.554 * max(dx, dy)

जो -5% और + 3% के बीच त्रुटियाँ देता है और + 0.043% की औसत त्रुटि


इस एल्गोरिथ्म के लिए एक नाम के लिए वेब पर खोज करते समय, मुझे यह समान अष्टकोणीय सन्निकटन मिला :

dist = 1007/1024 * max(dx, dy) + 441/1024 * min(dx, dy)

ध्यान दें कि यह अनिवार्य रूप से समतुल्य है (हालांकि प्रतिपादक अलग-अलग हैं - ये लोग -1.5% से 7.5% त्रुटि देते हैं, लेकिन इसे +/- 4% तक मालिश किया जा सकता है) max(dx, dy) + min(dx, dy) == dx + dy। इस फॉर्म का उपयोग करते हुए, minऔर maxकॉल को इसके पक्ष में उतारा जा सकता है:

if (dy > dx)
    swap(dx, dy)

dist = 1007/1024 * dx + 441/1024 * dy

क्या यह मेरे संस्करण से अधिक तेज़ है? कौन जानता है ... संकलक पर निर्भर करता है और यह लक्ष्य प्लेटफ़ॉर्म के लिए प्रत्येक को कैसे अनुकूलित करता है। मेरा अनुमान है कि किसी भी अंतर को देखना काफी मुश्किल होगा।


3
दिलचस्प है, यह पहले नहीं देखा है! क्या यह एक नाम है, या सिर्फ "चेबीशेव और मैनहट्टन का औसत" है?
कॉंगसबोंगस

@ congusbongus शायद इसका एक नाम है, लेकिन मुझे नहीं पता कि क्या है। यदि नहीं, तो शायद एक दिन इसे क्रिस्ट डिस्टेंस कहा जाएगा (
हाह

1
ध्यान दें कि फ्लोटिंग-पॉइंट गुणन बहुत कुशल नहीं हैं। इसीलिए अन्य सन्निकटन में 1007/1024 का उपयोग होता है (जिसे बिट शिफ्ट के बाद पूर्णांक गुणन के रूप में लागू किया जाएगा)।
MSalters

@MSalters हाँ, फ़्लोटिंग पॉइंट ऑपरेशन अक्सर पूर्णांक ऑपरेशनों की तुलना में धीमे होते हैं, लेकिन यह अप्रासंगिक है - 0.4 और 0.56 को आसानी से पूर्णांक संचालन का उपयोग करने के लिए परिवर्तित किया जा सकता है। इसके अलावा, आधुनिक x86 हार्डवेयर पर, सबसे चल बिन्दु आपरेशनों (अलावा अन्य FDIV, FSQRTऔर अन्य दिव्य कार्यों) लागत मूलतः एक ही उनके पूर्णांक संस्करणों के रूप में: अनुदेश प्रति 1 या 2 चक्र।
bcrist 24:14

1
यह अल्फा अधिकतम + बीटा मिन के समान दिखता है: en.wikipedia.org/wiki/Alpha_max_plus_beta_min_algorithm
drake7707

21

कभी-कभी यह सवाल दूरी की गणना करने की लागत के कारण नहीं उठ सकता है, लेकिन गणना की संख्या की वजह से किया जा रहा है।

कई अभिनेताओं के साथ एक बड़े खेल की दुनिया में , एक अभिनेता और अन्य सभी के बीच की दूरी को बनाए रखना अस्थिर है। अधिक खिलाड़ियों, NPCs और प्रोजेक्टाइल दुनिया में प्रवेश के रूप में, जरूरत है कि तुलना की संख्या बढ़ेगी किए जाने के लिए quadratically साथ ।O(N^2)

उस वृद्धि को कम करने का एक तरीका गणनाओं से अवांछित अभिनेताओं को जल्दी से छोड़ने के लिए एक अच्छी डेटा संरचना का उपयोग करना है।

हम उन सभी अभिनेताओं को कुशलता से पुनरावृत्त करने का एक रास्ता तलाश रहे हैं जो रेंज में हो सकते हैं, जबकि अधिकांश अभिनेताओं को छोड़कर जो निश्चित रूप से आउट-ऑफ-रेंज हैं

यदि आपके अभिनेता विश्व अंतरिक्ष में समान रूप से फैले हुए हैं, तो बाल्टी का एक ग्रिड एक उपयुक्त संरचना होना चाहिए (जैसा कि स्वीकृत उत्तर से पता चलता है)। मोटे ग्रिड में अभिनेताओं के संदर्भों को ध्यान में रखते हुए, आपको सभी अभिनेताओं को कवर करने के लिए केवल पास की कुछ बाल्टियों की जांच करने की आवश्यकता है, जो बाकी की अनदेखी करते हुए रेंज में हो सकती हैं। जब एक अभिनेता चलता है, तो आपको उसे अपनी पुरानी बाल्टी से एक नए स्थान पर ले जाने की आवश्यकता हो सकती है।

अभिनेताओं जो कम समान रूप से एक फैले हुए हैं के लिए quadtree एक दो आयामी दुनिया के लिए बेहतर कर सकता है, या एक octree एक तीन आयामी दुनिया के लिए उपयुक्त होगा। ये अधिक सामान्य उद्देश्य संरचनाएं हैं जो कुशलतापूर्वक खाली स्थान के बड़े क्षेत्रों, और बहुत सारे अभिनेताओं वाले छोटे क्षेत्रों को विभाजित कर सकती हैं। के लिए स्थिर अभिनेताओं है द्विआधारी अंतरिक्ष विभाजन (बसपा), जो खोजते हैं लेकिन अभी तक भी वास्तविक समय में अद्यतन करने के लिए महंगा करने के लिए बहुत तेजी से है। बीएसपी बार-बार इसे आधे हिस्से में काटने के लिए विमानों का उपयोग करके अंतरिक्ष को अलग करता है, और किसी भी संख्या में आयामों पर लागू किया जा सकता है।

बेशक आपके अभिनेताओं को इस तरह की संरचना रखने के लिए ओवरहेड्स हैं, खासकर जब वे विभाजन के बीच बढ़ रहे हैं। लेकिन कई अभिनेताओं के साथ एक बड़ी दुनिया में लेकिन ब्याज की छोटी श्रृंखला, लागत सभी वस्तुओं के मुकाबले भोली तुलना की तुलना में कम होनी चाहिए।

एल्गोरिथ्म का खर्च कैसे बढ़ता है, इस पर विचार करते हुए कि यह अधिक डेटा प्राप्त करता है, स्केलेबल सॉफ़्टवेयर डिज़ाइन के लिए महत्वपूर्ण है। कभी-कभी केवल सही डेटा संरचना का चयन करना ही पर्याप्त होता है। आमतौर पर बिग ओ नोटेशन का उपयोग करके लागत का वर्णन किया जाता है

(मुझे पता है कि यह सवाल का सीधा जवाब नहीं है, लेकिन यह कुछ पाठकों के लिए उपयोगी हो सकता है। यदि मेरा समय बर्बाद हो गया है तो मेरी माफी!)


7
यह सबसे अच्छा जवाब है। दूरी फ़ंक्शन में अनुकूलन करने के लिए कुछ भी नहीं है; बस इसे कम बार उपयोग करने की आवश्यकता है।
सैम होसेवर

3
स्वीकृत उत्तर स्थानिक विभाजन को भी कवर करता है, अन्यथा आपका उत्तर वास्तव में इष्टतम है। धन्यवाद।
ग्रिम्सव

मेरा समय आपके उत्तर को पढ़ने में बहुत अच्छा लगा। धन्यवाद, जॉय।
पैट्रिक एम

1
यह सबसे अच्छा जवाब है और केवल एक ही है जो वास्तविक समस्या पर ध्यान केंद्रित करता है, बजाय दूरस्थ फ़ंक्शन प्रदर्शन के रेड-हेरिंग के। स्वीकृत उत्तर अच्छी तरह से स्थानिक विभाजन को भी कवर कर सकता है, लेकिन यह एक तरफ के रूप में है; यह दूरी की गणना पर ध्यान केंद्रित करता है। दूरी गणना है नहीं प्राथमिक समस्या यहाँ; दूरी की गणना का अनुकूलन एक जानवर-बल गैर-समाधान है जो पैमाने पर नहीं होता है।
मैक्सिमस मिनिमस

क्या आप बता सकते हैं कि तुलनाओं की संख्या घातीय क्यों होगी? हालांकि, यह द्विघात होगा, प्रत्येक अभिनेता की हर समय सीमा के दौरान एक दूसरे के साथ तुलना करना।
पेट्र पुडलक

4

Chebyshev दूरी के बारे में कैसे? अंक p के लिए, इसे निम्नानुसार परिभाषित किया गया है:

दूरी

तो अंक (2, 4) और (8, 5) के लिए, चेबीशेव की दूरी 6 है, जैसा कि: 2-8 | > | 4-5 |

इसके अलावा, E को यूक्लिडियन दूरी और C को चेबीशेव दूरी होने दें। फिर:

distance2

ऊपरी बाउंड संभवतः अधिक उपयोग नहीं होता है क्योंकि आपको वर्गमूल की गणना करनी होगी, लेकिन निचला बाउंड सहायक हो सकता है - जब भी चेबिशेव की दूरी सीमा से बाहर होने के लिए पर्याप्त है, तो यूक्लिडियन दूरी भी होनी चाहिए, जिससे आपको बचत होगी इसकी गणना करने से।

व्यापार-बंद, निश्चित रूप से, अगर चेबीशेव दूरी सीमा के भीतर है, तो आपको यूक्लिडियन दूरी की गणना करना होगा, वैसे भी समय बर्बाद करना। केवल यह पता लगाने का एक तरीका है कि क्या यह एक शुद्ध जीत होगी!


1
आप ऊपरी हिस्से के रूप में मैनहट्टन की दूरी का भी उपयोग कर सकते हैं।
कॉंगसबोंगस

1
आधी हकीकत। मुझे लगता है कि वहाँ से केवल एक हॉप, स्किप और "चेब्शेव और मैनहट्टन के औसत" के लिए एक छलांग है, जैसा कि bcrist द्वारा सुझाया गया है।
तेतरीति

2

एक बहुत ही सरल स्थानीय अनुकूलन केवल पहले एक आयाम की जांच करना है।

अर्थात् :

distance ( x1, y1 , x1, y2) > fabs (x2 - x1)

तो बस fabs (x2 - x1)पहले फिल्टर के रूप में जाँच एक सराहनीय लाभ दे सकता है। विश्व के आकार बनाम संबंधित श्रेणियों पर कितना निर्भर करेगा।

इसके अलावा, आप इसे स्थानिक विभाजन डेटा संरचना के विकल्प के रूप में उपयोग कर सकते हैं।

यदि सभी प्रासंगिक वस्तुओं को x निर्देश क्रम में एक सूची में क्रमबद्ध किया जाता है, तो पास की वस्तुओं को सूची में पास होना चाहिए। यहां तक ​​कि अगर ऑब्जेक्ट पूरी तरह से बनाए रखने के कारण सूची क्रम से बाहर हो जाती है, तो गति की ज्ञात सीमाएं आप अभी भी पास के ऑब्जेक्ट के लिए खोज की जाने वाली सूची के अनुभाग को कम कर सकते हैं।


2

अनुकूलन करने के लिए अतीत में प्रयास किए गए थे sqrt। यद्यपि यह अब आज की मशीनों पर लागू नहीं होता है, यहां क्वेक स्रोत कोड का एक उदाहरण है, जो जादू की संख्या का उपयोग करता है 0x5f3759df:

float Q_rsqrt( float number )
{
  long i;
  float x2, y;
  const float threehalfs = 1.5F;

  x2 = number * 0.5F;
  y  = number;
  i  = * ( long * ) &y;  // evil floating point bit level hacking
  i  = 0x5f3759df - ( i >> 1 ); // what the hell?
  y  = * ( float * ) &i;
  y  = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
  // y  = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration (optional)
  // ...
  return y;
}

एक विस्तृत विवरण यहाँ क्या हो रहा है की विकिपीडिया पर पाया जा सकता है।

संक्षेप में, यह न्यूटन की विधि के कुछ पुनरावृत्तियों (एक संख्यात्मक एल्गोरिथ्म जो पुनरावृत्त रूप से एक अनुमान में सुधार करता है) है, एक उचित प्रारंभिक अनुमान प्रदान करने के लिए उपयोग किए जाने वाले जादू नंबर के साथ।

जैसा कि ट्रैविस बताते हैं, आधुनिक आर्किटेक्चर पर इस तरह का अनुकूलन अब उपयोगी नहीं है। और यहां तक ​​कि अगर यह था, तो यह केवल आपकी अड़चन को एक निरंतर दर गति प्रदान कर सकता है, जबकि एल्गोरिथम पुन: डिज़ाइन बेहतर परिणाम प्राप्त कर सकता है।


2
यह अब एक सार्थक अनुकूलन नहीं है। लगभग सभी उपभोक्ता-ग्रेड पीसी आर्किटेक्चर जिन्हें आप आजकल खरीद सकते हैं, हार्डवेयर-अनुकूलित sqrt निर्देश हैं जो एक घड़ी चक्र या उससे कम में वर्गमूल का प्रदर्शन करते हैं। यदि आपको वास्तव में सबसे तेज़ sqrt संभव है, तो आप x86 simd फ़्लोटिंग पॉइंट sqrt अनुदेश का उपयोग करते हैं: en.wikipedia.org/wiki/… GPU पर शेड्स जैसी चीज़ों के लिए, कॉल sqrt स्वचालित रूप से इस तरह के निर्देश का परिणाम होगा। सीपीयू पर, मुझे लगता है कि बहुत सारे कंपाइलर उपलब्ध होने पर SIMD sqrt के माध्यम से sqrt को लागू करते हैं।
ट्रैविसग

@TravisG हाँ जो ध्यान देने योग्य है, इसलिए मैंने उत्तर को अपडेट कर दिया है। यह उत्तर केवल मनोरंजन और ऐतिहासिक रुचि के लिए प्रदान किया गया था!
joeytwiddle
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.