मैं दो अक्षों पर किसी वस्तु को घुमा रहा हूं, तो यह तीसरी धुरी के आसपास क्यों घूमती रहती है?


38

मुझे लगता है कि प्रश्न अक्सर सामने आते हैं जिनमें यह अंतर्निहित मुद्दा होता है, लेकिन वे सभी किसी दिए गए विशेषता या उपकरण के विवरण में पकड़े जाते हैं। यहां एक कैनोनिकल उत्तर बनाने का प्रयास किया गया है, जब हम उपयोगकर्ताओं के लिए यह उल्लेख कर सकते हैं - बहुत सारे एनिमेटेड उदाहरणों के साथ! :)


मान लीजिए कि हम पहला व्यक्ति कैमरा बना रहे हैं। मूल विचार यह है कि बाईं और दाईं ओर देखना चाहिए, और ऊपर और नीचे देखने के लिए पिच होना चाहिए। तो हम इस तरह का एक सा कोड लिखते हैं (उदाहरण के रूप में एकता का उपयोग करते हुए):

void Update() {
    float speed = lookSpeed * Time.deltaTime;

    // Yaw around the y axis using the player's horizontal input.        
    transform.Rotate(0f, Input.GetAxis("Horizontal") * speed, 0f);

    // Pitch around the x axis using the player's vertical input.
    transform.Rotate(-Input.GetAxis("Vertical") * speed,  0f, 0f);
}

या हो सकता है

// Construct a quaternion or a matrix representing incremental camera rotation.
Quaternion rotation = Quaternion.Euler(
                        -Input.GetAxis("Vertical") * speed,
                         Input.GetAxis("Horizontal") * speed,
                         0);

// Fold this change into the camera's current rotation.
transform.rotation *= rotation;

और यह ज्यादातर काम करता है, लेकिन समय के साथ दृश्य कुटिल होने लगता है। लगता है कि कैमरा अपने रोल अक्ष (z) को चालू कर रहा है, भले ही हमने इसे केवल x और y पर घूमने के लिए कहा हो!

बग़ल में झुकाव वाले पहले व्यक्ति के कैमरे का एनिमेटेड उदाहरण

यह तब भी हो सकता है जब हम कैमरे के सामने किसी ऑब्जेक्ट में हेरफेर करने की कोशिश कर रहे हों - कहते हैं कि यह एक ऐसी दुनिया है जिसे हम चारों ओर देखने के लिए मुड़ना चाहते हैं:

बग़ल में झुकते हुए एक ग्लोब का अनुपम उदाहरण

वही समस्या - थोड़ी देर बाद उत्तरी ध्रुव बाईं या दाईं ओर घूमना शुरू कर देता है। हम दो अक्षों पर इनपुट दे रहे हैं, लेकिन हमें यह भ्रमित करने वाला रोटेशन तीसरे पर मिल रहा है। और ऐसा होता है कि क्या हम वस्तु के स्थानीय अक्षों या दुनिया के वैश्विक अक्षों के चारों ओर अपने सभी घुमावों को लागू करते हैं।

कई इंजनों में आप इसे इंस्पेक्टर में भी देखेंगे - दुनिया में ऑब्जेक्ट को घुमाएंगे, और अचानक संख्या एक अक्ष पर बदल जाती है जिसे हमने स्पर्श भी नहीं किया था!

एनिमेटेड उदाहरण जो अपने रोटेशन कोणों के एक रीडआउट के बगल में एक वस्तु में हेरफेर दिखा रहा है।  उपयोगकर्ता द्वारा उस अक्ष में हेरफेर न करने पर भी z कोण बदल जाता है।

तो, क्या यह इंजन बग है? हम उस प्रोग्राम को कैसे बताएंगे जो हम नहीं चाहते कि वह अतिरिक्त रोटेशन को जोड़े?

क्या यह यूलर एंगल्स के साथ कुछ करना है? क्या मुझे इसके बजाय Quaternions या Rotation Matrices या Basis Vectors का उपयोग करना चाहिए?



1
मुझे निम्नलिखित प्रश्न का उत्तर बहुत उपयोगी लगा। gamedev.stackexchange.com/questions/123535/…
ट्रैविस पेट्री

जवाबों:


51

नहीं, यह एक इंजन बग या किसी विशेष रोटेशन प्रतिनिधित्व की एक कलाकृति नहीं है (वे भी हो सकते हैं, लेकिन यह प्रभाव हर प्रणाली पर लागू होता है जो रोटेशन, quaternions का प्रतिनिधित्व करता है)।

आपने त्रि-आयामी अंतरिक्ष में रोटेशन कैसे काम करता है, इसके बारे में एक वास्तविक तथ्य की खोज की है, और यह अनुवाद जैसे अन्य परिवर्तनों के बारे में हमारे अंतर्ज्ञान से प्रस्थान करता है:

एनिमेटेड उदाहरण दिखा रहा है कि एक अलग क्रम में घुमावों को लागू करने से अलग परिणाम मिलते हैं

जब हम एक से अधिक अक्षों पर घुमावों की रचना करते हैं, तो हमें जो परिणाम मिलता है, वह प्रत्येक अक्ष पर हमारे द्वारा लागू कुल / शुद्ध मान नहीं है (जैसा कि हम अनुवाद के लिए उम्मीद कर सकते हैं)। जिस क्रम में हम घुमाव लगाते हैं, उसका परिणाम बदल जाता है, क्योंकि प्रत्येक घुमाव उन अक्षों को ले जाता है, जिन पर अगला घुमाव लागू होता है (यदि वस्तु के स्थानीय अक्षों के बारे में घूमता है), या वस्तु और अक्ष के बीच का संबंध (यदि दुनिया के बारे में घूमता है) कुल्हाड़ियों)।

समय के साथ अक्ष के रिश्तों का बदलना हमारे अंतर्ज्ञान को भ्रमित कर सकता है कि प्रत्येक अक्ष को क्या करना है। विशेष रूप से, जबड़े और पिच के घुमाव के कुछ संयोजन एक रोल रोटेशन के समान परिणाम देते हैं!

स्थानीय पिच-यॉ-पिच के अनुक्रम को दिखाने वाला एनिमेटेड उदाहरण एकल स्थानीय रोल के समान आउटपुट देता है

आप यह सत्यापित कर सकते हैं कि प्रत्येक चरण हमारे द्वारा अनुरोध की गई धुरी के बारे में सही तरीके से घूम रहा है - हमारे संकेतन में कोई इंजन गड़बड़ या विरूपण साक्ष्य नहीं है जो हमारे इनपुट के साथ हस्तक्षेप करता है या अनुमान लगाता है - घूर्णन की गोलाकार (या हाइपरस्पेरिकल / चतुर्धातुक) प्रकृति बस हमारे परिवर्तनों का अर्थ है "लपेटो" चारों ओर "एक दूसरे पर। वे छोटे रोटेशन के लिए स्थानीय रूप से ऑर्थोगोनल हो सकते हैं, लेकिन जैसा कि वे ढेर करते हैं हम पाते हैं कि वे विश्व स्तर पर ऑर्थोगोनल नहीं हैं।

यह 90-डिग्री के लिए सबसे नाटकीय और स्पष्ट है जो ऊपर की तरह बदल जाता है, लेकिन भटकते हुए कुल्हाड़ी कई छोटे घुमावों पर भी रेंगते हैं, जैसा कि प्रश्न में दिखाया गया है।

तो हम इस बारे में क्या कर सकते हैं?

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

यहाँ पिच-यॉ-पिच का वही क्रम है जो ऊपर दिए गए उदाहरण में एक रोल बन गया है, लेकिन अब हम अपने yaw को ऑब्जेक्ट के बजाय वैश्विक Y अक्ष पर लागू करते हैं

बिना किसी समस्या के स्थानीय पिच और ग्लोबल यव के साथ घूमने वाले मग का एनिमेटेड उदाहरणवैश्विक याओ का उपयोग करते हुए पहले व्यक्ति के कैमरे का एनिमेटेड उदाहरण

तो हम "Pitch Locally, Yaw Globally" मंत्र के साथ पहले व्यक्ति के कैमरे को ठीक कर सकते हैं:

void Update() {
    float speed = lookSpeed * Time.deltaTime;

    transform.Rotate(0f, Input.GetAxis("Horizontal") * speed, 0f, Space.World);
    transform.Rotate(-Input.GetAxis("Vertical") * speed,  0f, 0f, Space.Self);
}

यदि आप गुणन का उपयोग करके अपने घुमावों को कम कर रहे हैं, तो आप एक ही प्राप्त करने के लिए गुणा के बाएँ / दाएँ क्रम को फ्लिप करेंगे:

// Yaw happens "over" the current rotation, in global coordinates.
Quaternion yaw = Quaternion.Euler(0f, Input.GetAxis("Horizontal") * speed, 0f);
transform.rotation =  yaw * transform.rotation; // yaw on the left.

// Pitch happens "under" the current rotation, in local coordinates.
Quaternion pitch = Quaternion.Euler(-Input.GetAxis("Vertical") * speed, 0f, 0f);
transform.rotation = transform.rotation * pitch; // pitch on the right.

(विशिष्ट आदेश आपके वातावरण में गुणन सम्मेलनों पर निर्भर करेगा, लेकिन बाएं = अधिक वैश्विक / सही = अधिक स्थानीय एक सामान्य विकल्प है)

यह नेट टोटल यव और कुल पिच को संग्रहीत करने के बराबर है, जिसे आप फ्लोट वैरिएबल के रूप में चाहते हैं, फिर हमेशा नेट रिजल्ट को एक ही बार में लागू करते हुए, इन कोणों से एक ही नई अभिविन्यास चतुर्धातुक या मैट्रिक्स का निर्माण करते हैं (बशर्ते आप totalPitchताली बजाते रहें :

// Construct a new orientation quaternion or matrix from Euler/Tait-Bryan angles.
var newRotation = Quaternion.Euler(totalPitch, totalYaw, 0f);
// Apply it to our object.
transform.rotation = newRotation;

या समकक्ष ...

// Form a view vector using total pitch & yaw as spherical coordinates.
Vector3 forward = new Vector3(
                    Mathf.cos(totalPitch) * Mathf.sin(totalYaw),
                    Mathf.sin(totalPitch),
                    Mathf.cos(totalPitch) * Mathf.cos(totalYaw));

// Construct an orientation or view matrix pointing in that direction.
var newRotation = Quaternion.LookRotation(forward, new Vector3(0, 1, 0));
// Apply it to our object.
transform.rotation = newRotation;

इस वैश्विक / स्थानीय विभाजन का उपयोग करते हुए, घुमावों को एक-दूसरे को संयोजित करने और प्रभावित करने का मौका नहीं मिलता है, क्योंकि वे कुल्हाड़ियों के स्वतंत्र सेट पर लागू होते हैं।

वही विचार मदद कर सकता है यदि यह दुनिया में एक ऐसी वस्तु है जिसे हम घुमाना चाहते हैं। ग्लोब की तरह एक उदाहरण के लिए, हम अक्सर इसे उल्टा करना चाहते हैं और स्थानीय रूप से हमारे याओ को लागू करते हैं (इसलिए यह हमेशा अपने डंडों के चारों ओर घूमता है) और विश्व स्तर पर पिच करता है (इसलिए यह हमारे विचार से / दूर, बजाय ऑस्ट्रेलिया की ओर / दूर जाने के सुझाव देता है) , जहाँ भी यह इंगित कर रहा है ...)

बेहतर व्यवहार दिखाने वाले ग्लोब का एनिमेटेड उदाहरण

सीमाएं

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

इस तरह के मामलों में आप इसके बजाय क्या कर सकते हैं, जैसा कि हमने ऊपर प्रश्न में शुरू किया था, जैसे कि शुद्ध स्थानीय घुमाव का उपयोग करना है (इसलिए आपके नियंत्रण वही महसूस करते हैं जहां आप देख रहे हैं), जो शुरू में कुछ रोल रेंगने देगा - लेकिन फिर हम इसके लिए सही हैं।

उदाहरण के लिए, हम अपने "फॉरवर्ड" वेक्टर को अपडेट करने के लिए स्थानीय घुमाव का उपयोग कर सकते हैं, फिर उस फ़ाइनल वेक्टर का उपयोग हमारे अंतिम ओरिएंटेशन को बनाने के लिए "अप" वेक्टर के संदर्भ में कर सकते हैं। (उदाहरण के लिए, एकता का उद्धरण का उपयोग करना। लुब्रिकेशन विधि, या मैन्युअल रूप से इन वैक्टरों से एक ऑर्थोनॉमिक मैट्रिक्स का निर्माण करना) अप वेक्टर को नियंत्रित करके, हम रोल या ट्विस्ट को नियंत्रित करते हैं।

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


1
क्या मैं पूछ सकता हूं कि आपने जिफ कैसे बनाया? वे अच्छे लग रहे हैं।
बैलिंट

1
@ बैलिंट मैं एक मुफ्त कार्यक्रम का उपयोग करता है जिसे लिसेकैप कहा जाता है - यह आपको अपनी स्क्रीन के एक हिस्से को जिफ़ में रिकॉर्ड करने देता है। फिर मैं एनीमेशन ट्रिम कर देता हूं / अतिरिक्त कैप्शन टेक्स्ट जोड़ देता हूं / फ़ोटोशॉप का उपयोग करके GIF को संपीड़ित करता हूं।
DMGregory

क्या यह उत्तर केवल एकता के लिए है? क्या वेब पर अधिक सामान्य उत्तर है?
पॉज़फ़ान 12

2
@ posfan12 उदाहरण कोड समरूपता के लिए एकता सिंटैक्स का उपयोग करता है, लेकिन इसमें शामिल परिस्थितियां और गणित बोर्ड पर समान रूप से लागू होते हैं। क्या आपको अपने वातावरण के उदाहरणों को लागू करने में कोई कठिनाई हो रही है?
DMGregory

2
गणित पहले से ही ऊपर मौजूद है। आपके संपादन को देखते हुए, आप इसके गलत हिस्सों को मिटा रहे हैं। ऐसा लगता है कि आप यहां परिभाषित वेक्टर प्रकार का उपयोग कर रहे हैं । इसमें ऊपर वर्णित के अनुसार कोणों के एक सेट से रोटेशन मैट्रिक्स बनाने की एक विधि शामिल है। एक पहचान मैट्रिक्स के साथ शुरू करें और कॉल करें TCVector::calcRotationMatrix(totalPitch, totalYaw, identity)- यह ऊपर दिए गए "सभी एक बार यूलर" उदाहरण के बराबर है।
DMGregory

1

16 घंटे के पालन-पोषण और रोटेशन कार्यों के योग्य।

मैं बस चाहता था कि कोड एक खाली हो, मूल रूप से, हलकों में बदल रहा है और आगे की तरफ भी पलटता है।

या दूसरे शब्दों में, गोल पर बिना किसी प्रभाव के यव और पिच को घुमाना लक्ष्य है।

यहाँ कुछ हैं जो वास्तव में मेरे आवेदन में काम कर रहे हैं

एकता में:

  1. एक रिक्त बनाएँ। इसे ForYaw कहें।
  2. उस बच्चे को खाली दे दो, ForPitch कहा जाता है।
  3. अंत में, एक क्यूब बनाएं और इसे z = 5 (आगे) में ले जाएं। अब हम देख सकते हैं कि हम क्या बचने की कोशिश कर रहे हैं, जो क्यूब (आकस्मिक "रोल" जब हम जम्हाई और पिच करेंगे) को घुमाएंगे

अब Visual Studio में स्क्रिप्टिंग करें, अपना सेटअप करें, और अपडेट में इसे समाप्त करें:

objectForYaw.Rotate(objectForYaw.up, 1f, Space.World);
    objectForPitch.Rotate(objectForPitch.right, 3f, Space.World);

    //this will work on the pitch object as well
    //objectForPitch.RotateAround
    //    (objectForPitch.position, objectForPitch.right, 3f);

ध्यान दें कि यह सब मेरे लिए टूट गया जब मैंने पालन-पोषण के क्रम को बदलने की कोशिश की। या अगर मैं बच्चा पिच वस्तु के लिए Space.World को बदल दूं (पैरेंट Yaw को Space.Self के माध्यम से घुमाए जाने का मन नहीं है)। भ्रामक। मैं निश्चित रूप से कुछ स्पष्टीकरण का उपयोग कर सकता हूं कि मुझे एक स्थानीय अक्ष क्यों लेना था लेकिन इसे विश्व अंतरिक्ष के माध्यम से लागू करना चाहिए - क्यों Space.Self सब कुछ बर्बाद कर देता है?


यह मेरे लिए स्पष्ट नहीं है कि क्या इस सवाल का जवाब देने का इरादा है, या यदि आप यह समझने में मदद कर रहे हैं कि आपने जो कोड लिखा है, वह इस तरह क्यों काम करता है। यदि यह बाद की बात है, तो आपको एक नया प्रश्न पोस्ट करना चाहिए, यदि आप चाहें तो इस पेज को संदर्भ के लिए लिंक करें। एक संकेत के me.Rotate(me.right, angle, Space.World)रूप में me.Rotate(Vector3.right, angle, Space.Self, के रूप में ही है , और आपके नेस्टेड रूपांतर स्वीकार किए गए उत्तर में "पिच स्थानीय रूप से, यव ग्लोबली" उदाहरण के बराबर हैं।
DMGregory

थोड़ा दोनों। आंशिक रूप से उत्तर में साझा करने के लिए (जैसे कि यहां मेरे लिए कैसे काम किया गया है)। और सवाल भी पेश करना। वह इशारा मुझे मिल गया है। आपका बहुत बहुत धन्यवाद!
Jeh

कमाल है यह उत्कीर्ण नहीं किया गया था। घंटों के व्यापक उत्तर पढ़ने के बाद, हालांकि शैक्षिक अभी भी काम नहीं किया था, एक सामान्य वेक्टर 3 के बजाय ऑब्जेक्ट रोटेशन अक्ष का उपयोग करने का सरल उत्तर। सटीक अक्ष यह सब ऑब्जेक्ट पर तय रोटेशन को बनाए रखने के लिए लिया गया है। अतुल्य मैं जो देख रहा था उसे 0 वोटों के साथ दफन कर दिया गया था और Google के 2 पेज पर, इसी तरह के कई सवाल।
user4779
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.