SAT के साथ संपर्क बिंदु ढूँढना


12

अलग एक्सिस प्रमेय (सैट) न्यूनतम अनुवाद वेक्टर, यानी सबसे छोटा वेक्टर जो दो टकराने वाली वस्तुओं को अलग कर सकता है, को निर्धारित करना सरल बनाता है। हालाँकि, मुझे जो सदिश चाहिए वह सदिश वस्तुओं को सदिश के साथ अलग करता है कि मर्मज्ञ वस्तु गतिमान है (अर्थात संपर्क बिंदु)।

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

सैट आरेख

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

संपर्क बिंदु वेक्टर को खोजने के लिए एक सरल और / या अधिक कुशल तरीका है?


1
क्या आप सैट के उपयोग पर मृत हैं? एमपीआर (मिंकोव्स्की पोर्टल शोधन) जैसे एल्गोरिदम सीधे संपर्क को कई गुना पा सकते हैं। सैट और जीजेके के साथ, आपको संपर्क बिंदुओं की गणना करने के लिए एक अलग एल्गोरिथ्म की आवश्यकता होती है।
सीन मिडिलिचच

जवाबों:


6

आप जिस चीज के बारे में बात कर रहे हैं वह काफी कठिन है यदि आप इसे पहली बार किसी ऑब्जेक्ट को आगे बढ़ाने के रूप में संरचना करते हैं, तो टकराव के लिए परीक्षण करते हैं, तब तब तक बैकिंग करते हैं जब तक आप ऑब्जेक्ट से बाहर नहीं होते। गतिशील चौराहे परीक्षण के रूप में यह सोचना बेहतर है : एक स्थिर वस्तु के खिलाफ एक चलती वस्तु।

सौभाग्य से, अक्ष परीक्षण अलग करने से आपको यहाँ मदद मिल सकती है! यहाँ एल्गोरिथ्म का वर्णन है, रॉन लेविन के सौजन्य से :

एल्गोरिथ्म कुछ इस तरह है। आप दो उत्तल निकायों के सापेक्ष वेग वेक्टर के साथ काम करते हैं। दो अलग-अलग पिंडों और सापेक्ष वेग वेक्टर को t of पर एक विशेष पृथक्करण अक्ष पर दो-डी अंतराल और 1-D वेग प्रदान करना, जैसे कि यह बताना आसान है कि क्या दो अंतराल प्रतिच्छेद करते हैं, और यदि नहीं, तो वे अलग हो रहे हैं या एक साथ बढ़ रहे हैं। यदि वे अलग-अलग कुल्हाड़ियों में से किसी एक पर अलग हो रहे हैं (या, वास्तव में, किसी भी अक्ष पर), तो आप जानते हैं कि भविष्य में कोई टक्कर नहीं है। यदि किसी पृथक्करण अक्ष पर दो अनुमानित अंतराल t पर प्रतिच्छेद करते हैं₀ या अलग हो गए हैं और एक साथ आगे बढ़ रहे हैं, तो यह गणना करना आसान है (दो सरल 1D रैखिक अभिव्यक्तियों द्वारा) सबसे पहले भविष्य का समय, जिस पर दो अंतराल पहले प्रतिच्छेद करेंगे और (निरंतर आयताकार गति मानकर) नवीनतम भविष्य का समय जिसमें दोनों अंतराल चौराहे तक चलेगा और अलग होने लगेगा। (यदि वे टी ₀ पर इंटरसेक्ट कर रहे हैं तो भविष्य के शुरुआती चौराहे का समय टी are है)। यह सब अलग-अलग कुल्हाड़ियों के लिए करें। यदि भविष्य के चौराहे के समय के सभी अक्षों पर अधिकतम नवीनतम भविष्य के चौराहे के समय के सभी अक्षों की तुलना में न्यूनतम से कम है, तो भविष्य के अधिकतम चौराहे का समय दो 3 डी पॉलीहेड्रा की पहली टक्कर का सटीक समय है, अन्यथा भविष्य में कोई टकराव नहीं है।

दूसरे शब्दों में, आप उन सभी अक्षों के माध्यम से लूप करते हैं जो आप सामान्य रूप से एक स्थिर पृथक्करण अक्ष परीक्षण में करेंगे। अतिव्याप्ति के बजाय यदि आपको कोई ओवरलैप नहीं मिलता है, तो आप चलते रहते हैं और चलती वस्तु के अनुमानित वेग की जांच करते हैं । यदि यह स्थैतिक वस्तु से दूर जा रहा है, तो आप जल्दी से बाहर। अन्यथा, आप संपर्क के सबसे शुरुआती और नवीनतम समय को आसानी से हल कर सकते हैं (यह एक 1D अंतराल है जो दूसरे 1D अंतराल की ओर बढ़ रहा है)। यदि आप सभी अक्षों के लिए ऐसा करते हैं और अधिकतम चौराहे का समय और नवीनतम चौराहे के न्यूनतम समय को अधिकतम रखते हैं, तो आप जानते हैं कि आपकी चलती वस्तु स्थिर वस्तु से टकराएगी, साथ ही कब। तो आप अपनी गतिमान वस्तु को उस बिंदु तक ले जा सकते हैं जिस पर वह स्थिर वस्तु से टकराएगा।

यहाँ एल्गोरिथ्म के लिए कुछ मोटे और पूरी तरह से असत्यापित छद्मकोश हैं:

t_min := +∞
t_max := -∞
foreach axis in potential_separating_axes
    a_min := +∞
    a_max := -∞
    foreach vertex in a.vertices
        a_min = min(a_min, vertex · axis)
        a_max = max(a_max, vertex · axis)
    b_min := +∞
    b_max := -∞
    foreach vertex in b.vertices
        b_min = min(b_min, vertex · axis)
        b_max = max(b_max, vertex · axis)
    v := b.velocity · axis
    if v > 0 then
        if a_max < b_min then
            return no_intersection
        else if (a_min < b_min < a_max) or (b_min < a_min < b_max) then
            t_min = min(t_min, (a_max - b_min) / v)
            t_max = max(t_max, 0)
        else
            t_min = min(t_min, (a_max - b_min) / v)
            t_max = max(t_max, (a_min - b_max) / v)
    else if v < 0 then
        // repeat the above case with a and b swapped
    else if v = 0 then
        if a_min < b_max and b_min < a_max then
            t_min = min(t_min, 0)
            t_max = max(t_max, 0)
        else
            return no_intersection
if t_max < t_min then
    // advance b by b.velocity * t_max
    return intersection
else
    return no_intersection

यहाँ एक गामासूत्र लेख है जिसके बारे में कुछ अलग-अलग आदिम परीक्षणों के लिए लागू किया गया है। ध्यान दें कि SAT की तरह, इसके लिए उत्तल वस्तुओं की आवश्यकता होती है।

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


2
यह सब बहुत अच्छा है, लेकिन यह सीधे संपर्क के कई गुना की गणना के बारे में सवाल का जवाब नहीं देता है। इसके अलावा, अगर मैं इसे सही ढंग से समझता हूं, तो यह उत्तर केवल रैखिक वेग के साथ काम करता है, और इसलिए घूर्णन वस्तुओं का समर्थन नहीं कर सकता है; निश्चित नहीं है कि प्रश्न पूछने वाला ऐसा चाहता है या नहीं।
सीन मिडिलिचच

1
@seanmiddleditch यह सच है, यह फ्रेम पर घुमावों की उपेक्षा करता है। आपको शुरुआत में तुरंत घूमना होगा। लेकिन कोई भी तरीका जिसे मैं रूढ़िवादी प्रगति से कम जानता हूं, वास्तव में रोटेशन के साथ सटीक रूप से व्यवहार करता है। हालांकि, कोई रोटेशन नहीं दिया गया, यह संपर्क बिंदु का एक बेहतर अनुमान पैदा करता है।
बजे जॉन कलसेबेक

2

आप बहुभुज क्लिपिंग का उपयोग करना चाहते हैं। यह सबसे अच्छी तरह से चित्रों के साथ समझाया गया है, जो मेरे पास नहीं है, लेकिन इस आदमी ने किया, इसलिए मैं उसे समझाता हूं।

http://www.codezealot.org/archives/394

संपर्क कई गुना उस बिंदु पर एक बिंदु पर लौटेगा जो टकराव के लिए "सबसे अधिक जिम्मेदार" है, टक्कर का प्रत्यक्ष बिंदु नहीं। हालाँकि, आपको वास्तव में उस सीधी टक्कर की आवश्यकता नहीं है। आप बस पहले से मौजूद पैठ की गहराई और सामान्य का उपयोग करते हुए वस्तुओं को धक्का दे सकते हैं, और अन्य भौतिक प्रभावों को लागू करने के लिए संपर्क को कई गुना बढ़ा सकते हैं (उदाहरण के लिए, ढलान नीचे बॉक्स को रोल करें / बंद करें)।

ध्यान दें कि आपकी तस्वीर एक छोटी सी समस्या को दर्शाती है: जिस ब्लू वेक्टर पर आप पूछ रहे हैं, वह बिंदु किसी भी भौतिक सिमुलेशन में नहीं मिलेगा, क्योंकि यह वास्तव में नहीं है जहां बॉक्स हिट होगा। यह बॉक्स नीचे-बाएँ कोने से टकराएगा और ढलान को कहीं और छोड़ देगा क्योंकि कोने का एक छोटा सा हिस्सा घुसता है।

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


क्या आप जानते हैं कि क्या "ब्लू वेक्टर" की गणना करने का एक तरीका है (एसएटी का उपयोग करके वेग वेक्टर के साथ वस्तु को वापस आकार से बाहर करने के लिए आवश्यक है)?
तारा

@ डूडसन: सैट का उपयोग नहीं, नहीं। कि SAT क्या नहीं है। SAT आपको न्यूनतम पैठ की गहराई देता है, न कि पहला संपर्क किनारा। आपको लगता है कि आप जो पूछ रहे हैं, उसे करने के लिए आपको स्वेप्ट टकराव का पता लगाना होगा।
सीन मिडलडाइच

मुझे पता है कि सैट क्या करता है। मैंने पहले भी इसे लागू किया है। लेकिन मैं एक समस्या का सामना कर रहा हूं जो कि हल हो जाएगी अगर मैं बस पहले संपर्क किनारे की गणना करने के लिए SAT के आउटपुट का उपयोग कर सकता हूं। इसके अलावा "someguy" का उत्तर देखें। यह सुझाव देता है कि यह संभव है लेकिन इसे बहुत अच्छी तरह से नहीं समझाता।
तारा

@Dudeson: कम से कम पैठ के किनारे / धुरी आवश्यक रूप से पहले संपर्क के किनारे नहीं है, इसलिए मैं अभी भी नहीं देखता कि एसएटी कैसे मदद करता है। मैं इस विषय का विशेषज्ञ नहीं हूं, इसलिए मैं मानता हूं कि मैं गलत हो सकता हूं। :)
सीन मिडिलडच

बिल्कुल सही। इसलिए मुझे यकीन नहीं है कि यह संभव है। हालांकि, इसका मतलब यह होगा कि कुछ गुस्ताखी का जवाब गलत है। लेकिन वैसे भी मदद के लिए धन्यवाद! : डी
तारा

0

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


1
"मेट वेक्टर"? क्या आपका मतलब "एमटीवी" है?
तारा

0

मेरे जवाब के लिए कुछ दोहे हैं, कि मैं पहले रास्ते से हट जाऊंगा: यह केवल नॉन-रोटेटिंग बाउंडिंग बॉक्स से संबंधित है। यह मानता है कि आप टनलिंग के मुद्दों से निपटने की कोशिश कर रहे हैं, यानी वस्तुओं के कारण जो तेज गति से आगे बढ़ रहे हैं।

एक बार जब आप एमटीवी की पहचान कर लेते हैं, तो आप उस किनारे / सतह को सामान्य रूप से जानते हैं जिसके खिलाफ आपको परीक्षण करने की आवश्यकता है। आप इंटरपेंटरेटिंग ऑब्जेक्ट के रैखिक वेग वेक्टर को भी जानते हैं।

एक बार जब आप यह स्थापित कर लेते हैं कि फ्रेम के दौरान किसी बिंदु पर , एक चौराहा हुआ, तो आप निम्न आरंभिक बिंदुओं के आधार पर बाइनरी हाफ स्टेप ऑपरेशन कर सकते हैं: फ्रेम के दौरान पहले घुसे हुए शीर्ष को पहचानें:

vec3 vertex;
float mindot = FLT_MAX;
for ( vert : vertices )
{
    if (dot(vert, MTV) < mindot)
    {
         mindot = dot(vert, MTV);
         vertex = vert;
    }
}

एक बार जब आपने वर्टेक्स की पहचान कर ली है, तो द्विआधारी आधा कदम बहुत कम महंगा हो जाता है:

//mindistance is the where the reference edge/plane intersects it's own normal. 
//The max dot product of all vertices in B along the MTV will get you this value.
halfstep = 1.0f;
vec3 cp = vertex;
vec3 v = A.velocity*framedurationSeconds;
float errorThreshold = 0.01f; //choose meaningful value here
//alternatively, set the while condition to be while halfstep > some minimum value
while (abs(dot(cp,normal)) > errorThreshold)
{            
    halfstep*=0.5f;
    if (dot(cp,normal) < mindistance) //cp is inside the object, move backward
    {
        cp += v*(-1*halfstep);
    }
    else if ( dot(cp,normal) > mindistance) //cp is outside, move it forward
    {
        cp += v*(halfstep);
    }
}

return cp;

यह उचित रूप से सटीक है, लेकिन केवल एकल टकराव बिंदु प्रदान करेगा, एक ही मामले में।

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

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

दिलचस्प बात यह है कि यह आधा रास्ता विधि आपको (लगभग) सटीक समय भी दे सकती है कि ऑब्जेक्ट फ्रेम के दौरान हुआ था:

float collisionTime = frametimeSeconds * halfstep;

यदि आप किसी प्रकार की भौतिकी टक्कर संकल्प कर रहे हैं, तो आप A की स्थिति को सही कर सकते हैं:

v - (v*halfstep)

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.