एक क्षेत्र के बारे में मनमाना रोटेशन


12

मैं एक मैकेनिक को कोडित कर रहा हूं जो उपयोगकर्ता को एक गोले की सतह पर घूमने की अनुमति देता है। क्षेत्र पर स्थिति वर्तमान के रूप में संग्रहीत किया जाता है thetaऔर phi, जहां thetaz- अक्ष और वर्तमान स्थिति का XZ प्रक्षेपण बीच का कोण है (यानी y अक्ष के बारे में रोटेशन), और phiस्थिति के लिए y- अक्ष से कोण है। मैंने समझाया कि खराब, लेकिन यह अनिवार्य रूप से है theta = yaw,phi = pitch

Vector3 position = new Vector3(0,0,1);
position.X = (float)Math.Sin(phi) * (float)Math.Sin(theta);
position.Y = (float)Math.Sin(phi) * (float)Math.Cos(theta);
position.Z = (float)Math.Cos(phi);
position *= r;

मेरा मानना ​​है कि यह सही है, हालांकि मैं गलत हो सकता हूं। मुझे एक अनियंत्रित छद्म दो आयामी दिशा में स्थानांतरित करने में सक्षम होने की आवश्यकता है जो कि त्रिज्या से विश्व अंतरिक्ष की उत्पत्ति पर एक गोले की सतह के चारों ओर है r। उदाहरण के लिए, होल्डिंग Wको खिलाड़ी के उन्मुखीकरण के सापेक्ष एक ऊपर की दिशा में गोले के चारों ओर घूमना चाहिए।

मेरा मानना ​​है कि मुझे क्षेत्र पर स्थिति / अभिविन्यास का प्रतिनिधित्व करने के लिए एक Quaternion का उपयोग करना चाहिए, लेकिन मैं इसे करने के सही तरीके के बारे में नहीं सोच सकता। गोलाकार ज्यामिति मेरा मजबूत सूट नहीं है।

अनिवार्य रूप से, मुझे निम्नलिखित ब्लॉक भरने की आवश्यकता है:

public void Move(Direction dir)
{   
    switch (dir)
    {
        case Direction.Left:
            // update quaternion to rotate left
            break;
        case Direction.Right:   
            // update quaternion to rotate right
            break;
        case Direction.Up:
            // update quaternion to rotate upward
            break;
        case Direction.Down:
            // update quaternion to rotate downward
            break;
    }
}

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

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

अभी भी एक प्रश्न शेष है: क्या खिलाड़ी अभिविन्यास ("बाएं" और "दाएं" घुमा सकता है)?
मार्टिन सोज्का

हो सकता है कि मैं इसके लिए क्या करूं, इसका एक बेहतर उदाहरण: (1,1,1)बाईं ओर का खिलाड़ी गोले के चारों ओर घूमता हुआ (~1.2,0,~-1.2), फिर (-1,-1,-1), फिर (~-1.2,0,~1.2)और फिर वापस (1,1,1)
azz

1
आप हमेशा का ट्रैक रखने का इरादा है thetaऔर phiअपनी स्थिति को अद्यतन के रूप में, आप अपनी समस्या अनावश्यक रूप से जटिल बना रहे हैं। बहुत आसान बस 2 रोटेशन कुल्हाड़ियों की गणना करने के लिए प्रत्येक फ्रेम (जिनमें से एक (जबड़ा) कभी नहीं बदलता है) और Vector3.Transormगोले के आसपास। यह आपकी समस्या को सरल करेगा लेकिन आपको phi& के साथ डिस्कनेक्ट कर देगा theta
स्टीव एच।

जवाबों:


5

वास्तव में, यह पता चलता है कि आपके पास यह 'दोनों तरह' नहीं हो सकता है: यदि आपका इरादा क्षेत्र पर 'पूर्ण अभिविन्यास' की कोई भावना नहीं है (अर्थात, यदि खिलाड़ी हमेशा ध्रुवों की ओर नहीं होते हैं। ), तो आपको खिलाड़ी अभिविन्यास की धारणा की आवश्यकता होगी। इसका कारण यह है कि क्या अंतर्ज्ञान का सुझाव दे सकता के विपरीत, क्षेत्र पर आंदोलन है नहीं वास्तव में एक विमान पर आंदोलन की तरह, यहां तक कि स्थानीय स्तर पर नहीं (काफी); क्षेत्र के आंतरिक वक्रता का मतलब है कि खिलाड़ी ऐसी कार्रवाई कर सकते हैं जो खुद को घुमाएगी!

मैं जो बात कर रहा हूं, उसके सबसे चरम उदाहरण के लिए, कल्पना करें कि खिलाड़ी भूमध्य रेखा पर एक बिंदु पर शुरू होता है (सुविधा के लिए हम ऊपर से भूमध्य रेखा पर मैप की गई घड़ी की कल्पना करेंगे, और खिलाड़ी को 6 बजे डालेंगे। ), 'अप' का सामना करना - जो कि उत्तरी ध्रुव की ओर है। मान लीजिए कि खिलाड़ी उत्तरी ध्रुव की तरफ जाता है; फिर वे सीधे 12 बजे के बिंदु की ओर होंगे। अब, खिलाड़ी सीधे उत्तरी ध्रुव से भूमध्य रेखा की ओर अपने दाहिने ओर चलते हैं; वे 3 बजे बिंदु पर हवा करेंगे - लेकिन क्योंकि उनका सामना सही होने पर नहीं बदलता है(विचार यह है कि उनका सामना कोई फर्क नहीं पड़ता कि वे कैसे चलते हैं), वे अभी भी 12 बजे का सामना कर रहे हैं - वे अब भूमध्य रेखा के साथ सामना कर रहे हैं! अब, उन्हें 'बैकवर्ड' को उनके शुरुआती (6 बजे) बिंदु पर ले जाने दें; तब वे अभी भी भूमध्य रेखा के साथ सामना कर रहे हैं, इसलिए वे 3 बजे की ओर का सामना कर रहे होंगे - बस अपने 'व्यक्तिगत' अभिविन्यास को बदलने के बिना गोले के साथ आगे बढ़ने से उन्हें उत्तरी ध्रुव की ओर का सामना करने से घूमना पड़ेगा भूमध्य रेखा के साथ सामना! एक अर्थ में, यह पुराने का एक विस्तार है 'एक शिकारी एक मील दक्षिण, एक मील पश्चिम और फिर एक मील उत्तर' चुटकुला चलता है - लेकिन यहाँ हम दिशा के परिवर्तन को प्रभावित करने के लिए गोले की वक्रता का लाभ उठा रहे हैं। ध्यान दें कि एक ही प्रभाव अभी भी बहुत छोटे पैमाने पर होता है;

सौभाग्य से, quaternions करते हैं (जैसा कि आपने खुद को नोट किया है) इस स्थिति को संभालते हैं; चूंकि एक चतुर्भुज एक मनमाना रोटेशन का प्रतिनिधित्व करता है, यह प्रभावी रूप से क्षेत्र पर एक मनमाना 'प्लस प्लस ओरिएंटेशन' का प्रतिनिधित्व करता है: मूल में एक 'ट्राइक्सिस' से शुरू करने और इसे कुछ मनमाने ढंग से घुमाव देने की कल्पना करें, फिर एक इकाई को घुमाए गए दिशाओं में घुमाएं। जेड-अक्ष अंक; थोड़ा विचार आपको समझाएगा कि यह आपको इकाई क्षेत्र में एक बिंदु पर लाता है जिसमें कुछ 'अभिविन्यास' (यानी, आपके त्रिकोणीय के एक्स और वाई कुल्हाड़ियों की कुछ व्यवस्था) है, और यह कि आप हर बिंदु + उन्मुखीकरण पर प्राप्त कर सकते हैं इकाई इस तरह से घूमती है (बस अपने Z अक्ष को अपने बिंदु के माध्यम से मूल से रेखा के साथ इंगित करने के लिए असाइन करें, फिर अपने त्रिकोण को उस रेखा के साथ मूल में वापस ले जाएं)। इससे ज्यादा और क्या, चूंकि चतुर्भुज का गुणन घूर्णन की संरचना से मेल खाता है, इसलिए आपके द्वारा वर्णित प्रत्येक ऑपरेशन को आपके 'वर्तमान अभिविन्यास' को उचित रूप से चुने हुए चतुर्भुज से गुणा करके दर्शाया जा सकता है: विशेष रूप से, चूंकि (इकाई) चतुर्भुज (qx, qy, qz, qw) का अर्थ है 'आरक्यूओएस (क्यूडब्ल्यू) द्वारा एक्स (क्यूएक्स, क्यू, क्यूज़) अक्ष के बारे में घुमाएं, फिर (समन्वय प्रणाली की आपकी विशिष्ट पसंद पर निर्भर करता है, और c_a को cos (अल्फा) और s_a को पाप (अल्फा) होना चाहिए: दो तीन बटेर M_x = (s_a, 0, 0, c_a), M_y = (0, s_a, 0, c_a), और M_z = (0, 0, s_a, ca) उस दिशा में 'घुमाएँ (चाल') का प्रतिनिधित्व करेंगे। 'वर्तमान में अल्फा द्वारा सामना कर रहा हूँ' और 'वर्तमान में अल्फा द्वारा सामना कर रहा हूँ' के लिए एक दिशा में रूढ़िवादी घूमता हूँ। (उन quaternions का तीसरा प्रतिनिधित्व करेंगे 'अपने स्वयं के अक्ष के बारे में मेरे चरित्र को घुमाएगी'Cur_q = M_x * Cur_qयदि खिलाड़ी ने दबाव डाला है, या Cur_q = M_y * Cur_qयदि खिलाड़ी दाएं दबाया है (या संभवत: ऐसा कुछ है जैसे Cur_q = M_yinv * Cur_qकि खिलाड़ी बाईं ओर दबाया जाता है, जहां M_yinv M_y quaternion का 'उलटा' है, तो रोटेशन को दूसरे तरीके से दर्शाते हैं)। ध्यान दें कि आपको सावधान रहना होगा कि आप कौन सा 'पक्ष' पर रोटेशन लागू करते हैं, चाहे प्रीमोलिप्ली या पोस्टमुलिप्ली; स्पष्ट होने के लिए, परीक्षण और त्रुटि के साथ, दोनों गुणा की कोशिश करना और जो काम करता है उसे देखना आसान हो सकता है।

गोले के एक बिंदु (और अपने चरित्र के एक अभिविन्यास) पर अपने अद्यतन किए गए उद्धरण से जाना अपेक्षाकृत सरल है, भी: अंतिम पैराग्राफ के पत्राचार द्वारा, आपको बस इतना करना है कि अपने quaternion का उपयोग आधार वैक्टर (1) पर करें 0,0), (0,1,0) और (0,0,1) आपके फ्रेम के माध्यम से 'रोटेट वेक्टर बाइ क्वाटरनियन' ऑपरेशन v → qvq -1 (जहां गुणन यहां चतुष्कोणीय गुणन हैं और हम वेक्टर v की पहचान करते हैं) = (x, y, z) 'पतित चतुर्भुज' के साथ (x, y, z, 0))। उदाहरण के लिए, इकाई क्षेत्र पर स्थिति केवल z वेक्टर को बदलकर प्राप्त की जाती है: pos = (qx, qy, qz, qw) * (0, 0, 1, 0) * (-qx, -qy, -qz) qw) = (qx, qy, qz, qw) * (qy, -qx, qw, qz) = (2 (qy * qw + qz * qx), 2 (qz * qy-qw * qx), (qz ^) 2 + qw ^ 2) - (qx ^ 2 + qy ^ 2), 0), इसलिए(2(qy*qw+qz*qx), 2(qz*qy-qw*qx), (qz^2+qw^2)-(qx^2+qy^2))इकाई क्षेत्र पर 'रूपांतरित' उपयोगकर्ता के निर्देशांक होंगे (और एक मनमाना क्षेत्र पर निर्देशांक प्राप्त करने के लिए, निश्चित रूप से, आप बस उन क्षेत्रों को त्रिज्या से गुणा करेंगे); इसी तरह की गणना अन्य अक्षों के लिए काम करती है, उदाहरण के लिए उपयोगकर्ता के सामने की दिशा को परिभाषित करने के लिए।


वास्तव में मैं क्या हासिल करना चाहता हूं। मैं सिर्फ अभिविन्यास quaternion से बाहर एक स्थिति पाने के लिए सही तरीके के बारे में सोच नहीं सकता था। आपने जो प्रदान किया है, उसका उपयोग करते हुए, मैं Move()प्रक्रिया लिख सकता हूं , लेकिन सामान्यीकृत अक्ष (यानी मेरी स्थिति) प्राप्त करने के लिए, क्या मैं बस ले जाऊंगा (sin(qx),sin(qy),sin(qw)) * r?
azz

@ वास्तव में नहीं - मैं अपने पोस्ट को विवरणों के साथ अपडेट करूंगा, लेकिन संक्षिप्त संस्करण यह है कि आप अपने चतुर्भुज का उपयोग एक इकाई वेक्टर, उदाहरण के लिए (0,0,1), सामान्य v -> qvq <sup> द्वारा बदलने के लिए करते हैं। -1 </ sup> ऑपरेशन; तथ्य यह है कि आप एक साधारण वेक्टर को बदल रहे हैं इसका मतलब है कि (स्वाभाविक रूप से) यहां एक शॉर्ट-कट है, लेकिन अंतिम निर्देशांक आपके चतुर्भुज के मूल्यों में द्विघात हैं, रैखिक नहीं।
स्टीवन स्टैडनिक

1

मुझे लगता है कि आप इस http://www.youtube.com/watch?v=L2YRZbRSD1k के समान कुछ चाहते हैं

मैं एक 48h gamejam के लिए विकसित ... आप यहाँ कोड donwload कर सकते हैं ... http://archive.globalgamejam.org/2011/evil-god

मैंने 3D कोडर्स प्राप्त करने के लिए आपके कोड के समान कुछ का उपयोग किया ... लेकिन मैंने ग्रह को घुमाया और खिलाड़ी एक ही स्थिति में था, मुझे लगता है कि आप प्राणी आंदोलन में रुचि रखते हैं, क्या यह है:

    // To add movement
    protected override void LocalUpdate(float seconds)
    {
        Creature.Alfa += Direction.X * seconds * Speed;
        Creature.Beta += Direction.Y * seconds * Speed;            
    }


    // To calculate position
       World.Planet.GetCartesian(Alfa, Beta, out Position); // as you do
       Matrix PositionMatrix = Matrix.CreateTranslation(Position) * World.Planet.RotationMatrix;           
       LastPositionAbsolute = PositionAbsolute;
       Vector3 Up = PositionAbsolute = Vector3.Transform(Vector3.Zero, PositionMatrix);           
       Up.Normalize();
       // This is to add and offset to the creature model position
       PositionAbsolute += Up * 8;  
      // calculate new forward vector if needed

       if ((PositionAbsolute - LastPositionAbsolute).Length() > 0.1f) {
           Forward = PositionAbsolute - LastPositionAbsolute;
           Forward.Normalize();
       }

       // Calculate the world transform with position, forward vector and up vector
       Matrix LocalWorld = Matrix.CreateWorld(PositionAbsolute, Forward, Up); 

       Transform = Matrix.CreateScale(Scale * ScaleFactor) * LocalWorld;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.