मैं कैमरे के पीछे एक बिंदु कैसे सही ढंग से प्रोजेक्ट कर सकता हूं?


10

मैं एक 3 डी गेम बना रहा हूं जिसमें मैंने एक विस्मयबोधक चिह्न को ब्याज के ऊपर रखा है।

यह पता लगाने के लिए कि 2 डी स्क्रीन में मुझे अपना मार्कर कहां लगाना चाहिए, मैं मैन्युअल रूप से 3 डी बिंदु का अनुमान लगा रहा हूं जहां मार्कर होना चाहिए।

यह इस तरह दिख रहा है:

भयानक लग रहे मार्कर

बहुत अच्छा लग रहा है। जब मार्कर स्क्रीन के बाहर होता है, मैं बस निर्देशांक क्लिप करता हूं ताकि वे स्क्रीन में फिट हो सकें। यह इस तरह दिख रहा है:

मार्कर और भी भयानक लग रही है

अब तक यह विचार बहुत अच्छा चल रहा है। हालाँकि, जब रुचि के बिंदु कैमरे के पीछे होते हैं, तो परिणामी X, Y निर्देशांक उलटे होते हैं (जैसा कि धनात्मक / ऋणात्मक), और मुझे मार्कर स्क्रीन के विपरीत कोने पर दिखाई देता है, जैसे:

मार्कर इतने भयानक नहीं हैं

(अनुमानित-तब-क्लैम्प्ड बिंदु मार्कर की नोक है। मार्कर के रोटेशन को बुरा न मानें)

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

वर्तमान में यह मेरा प्रोजेक्शन कोड जैसा दिखता है (SharpDX के साथ C # में):

    public override PointF ProjectPosition(float viewportWidth, float viewportHeight, float y)
    {
        var projectionMatrix = Matrix.PerspectiveFovRH(GetCalibratedFOV(Camera.FOV, viewportWidth, viewportHeight), viewportWidth / viewportHeight, Camera.Near, Camera.Far);
        var viewMatrix = Matrix.LookAtRH(new Vector3(Camera.PositionX, Camera.PositionY, Camera.PositionZ), new Vector3(Camera.LookAtX, Camera.LookAtY, Camera.LookAtZ), Vector3.UnitY);
        var worldMatrix = Matrix.RotationY(Rotation) * Matrix.Scaling(Scaling) * Matrix.Translation(PositionX, PositionY, PositionZ);
        var worldViewProjectionMatrix = worldMatrix * viewMatrix * projectionMatrix;

        Vector4 targetVector = new Vector4(0, y, 0, 1);
        Vector4 projectedVector = Vector4.Transform(targetVector, worldViewProjectionMatrix);

        float screenX = (((projectedVector.X / projectedVector.W) + 1.0f) / 2.0f) * viewportWidth;
        float screenY = ((1.0f - (projectedVector.Y / projectedVector.W)) / 2.0f) * viewportHeight;
        float screenZ = projectedVector.Z / projectedVector.W;

        // Invert X and Y when behind the camera
        if (projectedVector.Z < 0 ||
            projectedVector.W < 0)
        {
            screenX = -screenX;
            screenY = -screenY;
        }

        return new PointF(screenX, screenY);
    }

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

मार्करों आधा भयानक

मैंने कोशिश की है जब:

  • Z नकारात्मक है (यह वही है जो मेरे लिए सबसे ज्यादा मायने रखता है)
  • W नकारात्मक है (मैं नकारात्मक W मान का अर्थ नहीं समझता)
  • या तो Zया Wनकारात्मक है (जो वर्तमान में समय के सबसे अधिक काम कर रहा है)
  • Zऔर Wअलग संकेत के हैं, उर्फ: Z / W < 0(मेरे लिए समझ में आता है। हालांकि काम नहीं करता है)

लेकिन अभी भी एक सुसंगत तरीका नहीं मिला है जिसके साथ मेरे सभी बिंदु सही ढंग से अनुमानित हैं।

कोई विचार?

जवाबों:


2

इसे थोड़ा अलग तरीके से करने के बारे में कैसे?

हमेशा की तरह शुरू करें और व्यूपोर्ट में सभी मार्करों को प्रस्तुत करें। यदि कोई व्यूपोर्ट के बाहर मार्कर है - आगे बढ़ें:

  1. मार्कर की स्थिति प्राप्त करें A
  2. कैमरे की स्थिति प्राप्त करें B(शायद इसके सामने थोड़ा)
  3. ABइन दोनों के बीच 3 डी वेक्टर की गणना करें
  4. उस वेक्टर को 2D स्क्रीन सीमा में रूपांतरित और सामान्य करें ( Aव्यू सेंटर में Bहोगा और व्यू बॉर्डर को हिट करेगा)

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

रंग रेखाएं ABवैक्टर हैं। पतली काली रेखाएं वर्ण की ऊंचाइयां हैं। दाईं ओर 2 डी स्क्रीन है

  1. शायद एक नियम जोड़ें, कि कैमरे के पीछे सब कुछ हमेशा नीचे के किनारे पर जाता है
  2. मार्कर के आकार और ओवरलैप के संबंध में स्क्रीन स्पेस में मार्कर को ड्रा करें

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


वह चरण 4 वास्तव में कैसे काम करेगा?
पांडा पाजामा

@PandPajama: मैंने जवाब में थोड़ा जोड़ा है। क्या यह अब अधिक स्पष्ट है?
क्रॉमस्टर

ज़रुरी नहीं। आप वेक्टर को कैसे "परिवर्तित और सामान्य" कर रहे हैं? यदि वह एक प्रक्षेपण मैट्रिक्स लागू करने से है, तो आप वही काम कर रहे हैं जो मैं कर रहा हूं
पांडा पायजामा

@PandaPajama: जहां तक ​​मैं समझता हूं कि आप इसे कैमरा-स्पेस (इसलिए नकारात्मक ZW समस्या) में कर रहे हैं। मैं इसे विश्व अंतरिक्ष में करने का सुझाव देता हूं और उसके बाद ही स्क्रीन-स्पेस में परिवर्तित होता हूं।
क्रॉम्स्टर

लेकिन, क्या ABमैं गणना करके , क्या मैं दुनिया के निर्देशांक को कैमरे के निर्देशांक से परिवर्तित नहीं कर रहा हूं?
पांडा पायजामा

1

तीन वैक्टर को देखते हुए [camera position], [camera direction]और [object position]। के डॉट उत्पाद की गणना करें [camera direction]और [object position]-[camera position]। यदि परिणाम नकारात्मक है, तो वस्तु कैमरे के पीछे है।

यह देखते हुए कि मैंने आपका कोड सही समझा है:

if((PositionX - Camera.PositionX) * Camera.LookAtX
    + (PositionY - Camera.PositionY) * Camera.LookAtY
    + (PositionZ - Camera.PositionZ) * Camera.LookAtZ
    < 0)

Yहै PositionY + (y * Scaling)। मैं इसे आज रात दे दूँगा
पांडा पाजामा

इससे मैं वास्तव में जान सकता हूं कि कैमरे के पीछे बिंदु कब है। हालांकि, यह प्रक्षेपण को Z = 0 पर एक विलक्षणता तक पहुंचने से नहीं रोकता है।
पांडा पजामा

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

0

केवल परीक्षण (अनुमानित। <0), नहीं (जेड <0 || डब्ल्यू <0)।

कुछ क्लिप स्पेस फॉर्मुलेशन ( कफ ओपनल कफ ) में, दृश्यमान रेंज में सकारात्मक और नकारात्मक Z मान शामिल होते हैं, जबकि W हमेशा कैमरे के सामने सकारात्मक होता है और पीछे नकारात्मक।


मैंने केवल W <0 के साथ प्रयास किया है, लेकिन अभी भी ऐसे स्थान हैं जहां यह गलत तरीके से अनुमानित है।
पांडा पायजामा

0
float screenX = (((projectedVector.X / abs(projectedVector.W)) + 1.0f) / 2.0f) * viewportWidth;
float screenY = ((1.0f - (projectedVector.Y / abs(projectedVector.W))) / 2.0f) * viewportHeight;

और इस हिस्से को हटा दें

// Invert X and Y when behind the camera
if (projectedVector.Z < 0 || projectedVector.W < 0)
{
    screenX = -screenX;
    screenY = -screenY;
}

-2

एक बिलबोर्ड का प्रयास करें, जो स्वचालित रूप से तस्वीर को कैमरे का सामना कर देगा, और स्वचालित रूप से उचित स्थान पर स्क्रीन पर तस्वीर खींच देगा


3
क्या आपने प्रश्न पढ़ा है?
क्रॉम्स्टर

क्षमा करें, मुझे समझाएं - बिलबोर्ड का आउटपुट लेना, स्केलिंग से छुटकारा पाना संभव है, (इसलिए यह 2D है लेकिन 3D स्थिति का अनुसरण करता है), और फिर इसे कुछ मैट्रिक्स गणित का उपयोग करके स्क्रीन की सीमा में रखें।
माइकल लैंगफोर्ड

सवाल विशेष रूप से "और फिर इसे कुछ मैट्रिक्स गणित का उपयोग करके स्क्रीन की सीमा में रखें "
क्रॉम्स्टर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.