एक लक्ष्य का सामना करने के लिए एक मॉडल ओरिएंटिंग


28

मेरे पास दो ऑब्जेक्ट्स (लक्ष्य और खिलाड़ी) हैं, दोनों की स्थिति (वेक्टर 3) और रोटेशन (क्वाटरनियन) है। मैं चाहता हूं कि खिलाड़ी पर निशाना सही और घुमाया जाए। लक्ष्य, जब यह कुछ शूट करता है तो खिलाड़ी को सही शूट करना चाहिए।

मैंने खिलाड़ी को थप्पड़ मारने के बहुत सारे उदाहरण देखे हैं, लेकिन मैं वृद्धिशील रोटेशन नहीं चाहता, ठीक है, मुझे लगता है कि जब तक मैं 100% कर सकता हूं, तब तक यह ठीक होगा, और जब तक यह वास्तव में काम करता है।

FYI करें - अन्य चीजों को करने के लिए स्थिति और रोटेशन का उपयोग करने में सक्षम है और यह अंतिम टुकड़ा I खिचड़ी भाषा को छोड़कर यह सब बहुत अच्छा काम करता है।

लक्ष्य के वर्ग में कोड नमूने चलते हैं, स्थिति = लक्ष्य की स्थिति, अवतार = खिलाड़ी।

संपादित करें

Im अब Maik के c # कोड का उपयोग कर रहा है जो उसने प्रदान किया है और यह बहुत अच्छा काम करता है!


4
यदि आप 100% थप्पड़ मार रहे हैं, तो आप थप्पड़ का उपयोग नहीं कर रहे हैं। आप केवल रोटेशन को 0*(rotation A) + 1*(rotation B)दूसरे शब्दों में सेट कर रहे हैं, आप बस रोटेशन को रोटेशन के लिए B लंबा रास्ता तय कर रहे हैं। बीच में जिस तरह से रोटेशन (0% <x <100%) दिखना चाहिए, यह निर्धारित करने के लिए स्लरप केवल है।
doppelgreener

ठीक है, समझ में आता है, लेकिन, लक्ष्य अभी भी पूरी तरह से खिलाड़ी की ओर नहीं घूम रहा है ... उस कोड के साथ "लंबा रास्ता"।
मार्क

जवाबों:


20

इसे करने के एक से अधिक तरीके हैं। आप अपने अवतार के सापेक्ष पूर्ण अभिविन्यास या घूर्णन की गणना कर सकते हैं, जिसका अर्थ है कि आपका नया उन्मुखीकरण = avatarOrientation * q। यहाँ एक बाद है:

  1. अपने अवतार की यूनिट फॉरवर्ड वेक्टर के क्रॉस प्रोडक्ट और अवतार से यूनिट वेक्टर को लक्ष्य तक ले जाने के लिए रोटेशन अक्ष की गणना करें।

    vector newForwardUnit = vector::normalize(target - avatarPosition);
    vector rotAxis = vector::cross(avatarForwardUnit, newForwardUnit);
  2. डॉट-उत्पाद का उपयोग करके रोटेशन कोण की गणना करें

    float rotAngle = acos(vector::dot(avatarForwardUnit, newForwardUnit));
  3. रोटाक्सिस और रोटएंगल का उपयोग करके बटेरियन बनाएं और इसे अवतार के वर्तमान अभिविन्यास के साथ गुणा करें

    quaternion q(rotAxis, rotAngle);
    quaternion newRot = avatarRot * q;

अगर आपको अवतार के वर्तमान फॉरवर्ड वेक्टर को खोजने में मदद की आवश्यकता है, तो इनपुट के लिए 1. बस शूट :)

संपादित करें: पूर्ण अभिविन्यास की गणना करना वास्तव में थोड़ा आसान है, 1) और 2 के इनपुट के रूप में अवतारों के आगे वेक्टर के बजाय पहचान-मैट्रिक्स के आगे वेक्टर का उपयोग करें। और इसे 3 में गुणा न करें), इसके बजाय इसे सीधे नए अभिविन्यास के रूप में उपयोग करें:newRot = q


नोट करने के लिए महत्वपूर्ण: समाधान में क्रॉस-उत्पाद की प्रकृति के कारण 2 विसंगतियां हैं:

  1. अगर आगे वाले वैक्टर बराबर हैं। यहाँ समाधान केवल पहचान के लिए वापसी है

  2. यदि वैक्टर विपरीत दिशा में बिल्कुल इंगित करता है। यहाँ समाधान यह है कि अवतारों को अक्ष के रूप में रोटेशन अक्ष और कोण 180.0 डिग्री का उपयोग करके चतुर्धातुक बनाना है।

यहाँ C ++ में कार्यान्वयन है जो उन बढ़त मामलों की देखभाल करता है। इसे C # में बदलना आसान होना चाहिए।

// returns a quaternion that rotates vector a to vector b
quaternion get_rotation(const vector &a, const vector &b, const vector &up)
{   
    ASSERT_VECTOR_NORMALIZED(a);
    ASSERT_VECTOR_NORMALIZED(b);

    float dot = vector::dot(a, b);    
    // test for dot -1
    if(nearly_equal_eps_f(dot, -1.0f, 0.000001f))
    {
        // vector a and b point exactly in the opposite direction, 
        // so it is a 180 degrees turn around the up-axis
        return quaternion(up, gdeg2rad(180.0f));
    }
    // test for dot 1
    else if(nearly_equal_eps_f(dot, 1.0f, 0.000001f))
    {
        // vector a and b point exactly in the same direction
        // so we return the identity quaternion
        return quaternion(0.0f, 0.0f, 0.0f, 1.0f);
    }

    float rotAngle = acos(dot);
    vector rotAxis = vector::cross(a, b);
    rotAxis = vector::normalize(rotAxis);
    return quaternion(rotAxis, rotAngle);
}

EDIT: मार्क के XNA कोड का सही संस्करण

// the new forward vector, so the avatar faces the target
Vector3 newForward = Vector3.Normalize(Position - GameState.Avatar.Position);
// calc the rotation so the avatar faces the target
Rotation = Helpers.GetRotation(Vector3.Forward, newForward, Vector3.Up);
Cannon.Shoot(Position, Rotation, this);


public static Quaternion GetRotation(Vector3 source, Vector3 dest, Vector3 up)
{
    float dot = Vector3.Dot(source, dest);

    if (Math.Abs(dot - (-1.0f)) < 0.000001f)
    {
        // vector a and b point exactly in the opposite direction, 
        // so it is a 180 degrees turn around the up-axis
        return new Quaternion(up, MathHelper.ToRadians(180.0f));
    }
    if (Math.Abs(dot - (1.0f)) < 0.000001f)
    {
        // vector a and b point exactly in the same direction
        // so we return the identity quaternion
        return Quaternion.Identity;
    }

    float rotAngle = (float)Math.Acos(dot);
    Vector3 rotAxis = Vector3.Cross(source, dest);
    rotAxis = Vector3.Normalize(rotAxis);
    return Quaternion.CreateFromAxisAngle(rotAxis, rotAngle);
}

ठीक है, मैंने एक शॉट दिया, जैसा कि आप प्रश्न में मेरे संपादन द्वारा देख सकते हैं, प्रदान किया गया कोड। वास्तव में निश्चित नहीं है कि समस्या क्या है। ए और बी इनपुट फॉरवर्ड वैक्टर हैं, या कम से कम माना जाता है।
मार्क

@ मेरा जवाब में अपने XNA कोड का मेरा सही संस्करण देखें। 2 समस्याएं थीं: 1) नए फॉरवर्ड वेक्टर की गणना गलत थी, अवतारवाद को सामान्य किया जाना चाहिए - लक्ष्यपोजिशन 2) GetRotation में क्रॉस-उत्पाद के बाद रोटैक्स को सामान्य किया जाना चाहिए
Maik Semder

@Marc, 2 मामूली बदलाव: 3) स्रोत और भाग्य पहले से ही सामान्यीकृत हैं, GetRotation में उन्हें फिर से सामान्य करने की कोई आवश्यकता नहीं है) GetRotation में निरपेक्ष 1 / -1 के लिए न ही परीक्षण करें, बल्कि कुछ सहिष्णुता का उपयोग करें, मैंने 0.00002f का उपयोग किया
Maik Semder

हम्म, अभी भी काम नहीं कर रहा है। मॉडल के साथ एक ही स्केलिंग वाली बात होती है और टारगेट फ्लॉप अवतार की ओर घूमता है (जो मैंने आपकी टिप्पणियों में देखा था कि आप टारगेट की ओर अवतार को घुमाने की कोशिश कर रहे हैं .... चारों ओर दूसरा रास्ता होना चाहिए) ... मूल रूप से, कोशिश कर रहा है खिलाड़ी का सामना करने के लिए एक भीड़ पाने के लिए (एक तीसरे व्यक्ति के कैमरे में अवतार)। क्या GetRotation पद्धति को लक्ष्य और अवतार के वर्तमान घुमावों के बारे में कुछ नहीं पता होना चाहिए, जैसा कि आपको लगता है कि newForward को ठीक से बनाया जा रहा है?
मार्क

यदि ऑब्जेक्ट को स्केल किया जाता है, तो इसका मतलब है कि quaternion की एक इकाई लंबाई नहीं है, इसका मतलब है कि रोटैक्सिस सामान्यीकृत नहीं है। क्या आपने रोटाएक्सिस के सामान्यीकरण के साथ मेरा आखिरी कोड-परिवर्तन जोड़ा? हालाँकि, कृपया अपना वर्तमान कोड दिखाएं और एक उदाहरण के मामले में जहां यह काम नहीं करता है, कृपया: newForward rotAngle rotAxisऔर a का मान भी पोस्ट करें returned quaternion। भीड़ के लिए कोड समान होगा, एक बार जब हमने इसे अवतार के साथ काम किया, तो किसी भी वस्तु के शीर्षक को बदलना आसान होगा।
माईक सेमर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.