स्कैन के साथ, z- बफर के लिए गहराई से प्रक्षेप


10

मुझे अपना खुद का सॉफ्टवेयर 3D रेस्टराइज़र लिखना होगा, और अब तक मैं अपने 3D मॉडल को त्रिभुजों से बना कर प्रोजेक्ट में सक्षम कर रहा हूँ:

मैं प्रत्येक त्रिभुज का 2d स्थान प्रतिनिधित्व प्राप्त करने के लिए अपने बिंदुओं को घुमाता हूं, अनुवाद करता हूं और प्रोजेक्ट करता हूं। फिर, मैं 3 त्रिभुज बिंदु लेता हूं और मैं सभी बिंदुओं को खोजने के लिए स्कैनलाइन एल्गोरिथ्म (रैखिक प्रक्षेप का उपयोग करके) को लागू करता हूं [x] [y] त्रिकोण के किनारों (बाएं और दाएं) के साथ, ताकि मैं त्रिभुज को क्षैतिज रूप से स्कैन कर सकूं, पंक्ति से पंक्ति, और इसे पिक्सेल से भरें।

यह काम। सिवाय मुझे z- बफरिंग लागू करने के भी। इसका मतलब है कि त्रिकोण के 3 कोने के घुमाए गए और अनुवादित z निर्देशांक को जानने के बाद, मुझे अपने स्कैनलाइन एल्गोरिथ्म के साथ मिलने वाले अन्य सभी बिंदुओं के लिए z समन्वय को प्रक्षेपित करना होगा।

अवधारणा पर्याप्त स्पष्ट लगती है, मैं पहली बार ज़ा और जेडबी को इन गणनाओं के साथ देखता हूं:

var Z_Slope = (bottom_point_z - top_point_z) / (bottom_point_y - top_point_y);
var Za = top_point_z + ((current_point_y - top_point_y) * Z_Slope);

फिर प्रत्येक Zp के लिए मैं एक ही प्रक्षेप क्षैतिज रूप से करता हूं:

var Z_Slope = (right_z - left_z) / (right_x - left_x);
var Zp = left_z + ((current_point_x - left_x) * Z_Slope);

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

और यदि वर्तमान z उस सूचकांक पर पिछले z की तुलना में दर्शक के करीब है, तो रंग को रंगीन बफर में लिखें और z z को बफर में नया लिखें। (मेरा समन्वय प्रणाली x है: बाएँ -> दाएँ; y: शीर्ष -> नीचे; z: आपका चेहरा -> कंप्यूटर स्क्रीन;)

समस्या यह है, यह haywire जाता है। यह परियोजना यहां है और यदि आप "Z-Buffered" रेडियो बटन का चयन करते हैं, तो आपको परिणाम दिखाई देंगे ... ( ध्यान दें कि मैं "Z-Buffered" मोड में चित्रकार के एल्गोरिथ्म का उपयोग करता हूं (-only- वायरफ्रेम खींचने के लिए) डिबगिंग उद्देश्यों के लिए )

पुनश्च: मैंने यहाँ पढ़ा है कि आप को z = 1/zप्रक्षेप करने से पहले z को उनके पारस्परिक (अर्थ ) में बदल देना चाहिए । मैंने कोशिश की है, और ऐसा लगता है कि कोई बदलाव नहीं है। मैं क्या खो रहा हूँ? (कोई भी स्पष्ट कर सकता है, ठीक है जहां आपको z को 1 / z में बदलना चाहिए और जहां (यदि) उसे वापस चालू करना है?)

[संपादित करें] यहां मुझे अधिकतम और न्यूनतम z मानों के बारे में कुछ डेटा दिए गए हैं:

    max z: 1;                  min z: -1;                 //<-- obvious, original z of the vertices of the triangles
    max z: 7.197753398761272;  min z: 3.791703256899924;   //<-- z of the points that were drawn to screen (you know, after rotation, translation), by the scanline with zbuffer, gotten with interpolation but not 1/z.
    max z: 0.2649908532179404; min z: 0.13849507306889008;//<-- same as above except I interpolated 1/z instead of z.
//yes, I am aware that changing z to 1/z means flipping the comparison in the zBuffer check. otherwise nothing gets drawn.

इससे पहले कि मैं श्रमसाध्य डिबगिंग में जाऊं, क्या कोई पुष्टि कर सकता है कि मेरी अवधारणा अब तक सही है?

[EDIT2]

मैंने z- बफ़रिंग को हल किया है। जैसा कि यह पता चला है, ड्राइंग ऑर्डर बिल्कुल गड़बड़ नहीं था। Z निर्देशांक की सही गणना की जा रही थी।

समस्या यह थी कि अपने फ्रेम दर को बढ़ाने के प्रयास में, मैं स्क्रीन पर वास्तविक पिक्सेल के बजाय हर 4 पिक्सेल को 4px / 4px बक्से खींच रहा था। इसलिए मैं 16 पिक्सेल प्रति पिक्सेल खींच रहा था, लेकिन उनमें से केवल एक के लिए z बफर की जाँच कर रहा था। मैं ऐसा उल्लू हूँ।

टीएल / डीआर: सवाल अभी भी खड़ा है: आपको जेड के बजाय जेड (1 / जेड में) के पारस्परिक उपयोग का उपयोग कैसे / क्यों / कब करना है? क्योंकि अभी, सब कुछ या तो काम करता है। (कोई ध्यान देने योग्य अंतर नहीं है)।


पुन: "और निश्चित रूप से मैं zBuffer में जोड़ता हूं, यदि वर्तमान z उस सूचकांक में पिछले मान की तुलना में दर्शक के करीब है।" इसका मुझे यह स्पष्ट नहीं है कि आपने यह कहा था कि आप कैसे थे, लेकिन यह सुनिश्चित करना चाहते थे कि आपका क्या मतलब था "अगर वर्तमान z उस सूचकांक में पिछले z की तुलना में दर्शक के करीब है, तो रंग को रंगीन बफर में लिखें और लिखें। z बफ़र के लिए नया z "z बफ़र का उद्देश्य रंग लिखना है यदि उस पिक्सेल पर एक रंग पहले ही कैमरे की आंख के करीब लिखा गया था।
2

वह सही है। क्षमा करें, जब मैंने अपने प्रश्न को सुना तो देर हो चुकी थी। मैं संशोधित करूंगा।
स्पेक्ट्रलजंप 10

जवाबों:


5

त्वरित उत्तर: Z (X ', Y') का रैखिक कार्य नहीं है, लेकिन 1 / Z है। चूंकि आप रैखिक रूप से प्रक्षेपित करते हैं, इसलिए आपको 1 / Z के लिए सही परिणाम मिलते हैं, लेकिन Z के लिए नहीं।

आप ध्यान नहीं देते क्योंकि जब तक Z1 और Z2 के बीच तुलना सही है, तब तक ज़फ़र सही काम करेगा, भले ही दोनों मान गलत हों। जब आप बनावट मैपिंग जोड़ते हैं, तो आप निश्चित रूप से नोटिस करेंगे (और तब आपके पास मौजूद प्रश्न का उत्तर देने के लिए: 1 / Z, U / Z और V / Z को इंटरपोल करें और इन मानों से U और V का पुनर्निर्माण करें: U = (U / Z) / (1 / जेड), वी = (वी / जेड) / (1 / जेड)। आप मुझे बाद में धन्यवाद देंगे)

एक उदाहरण। कागज का एक टुकड़ा प्राप्त करें। टॉप-डाउन दृश्य, इसलिए वाई समन्वय को भूल जाएं। X क्षैतिज अक्ष है, Z ऊर्ध्वाधर अक्ष है, कैमरा (0, 0) पर है, प्रक्षेपण विमान z = 1 है।

अंक ए (-2, 2) और बी (2, 4) पर विचार करें। खंड AB का मध्य बिंदु M (0, 3) है। अब तक सब ठीक है।

आप A को A ': X' = X / Z = -1 में प्रोजेक्ट करते हैं, इसलिए A '(-1, 1) है। इसी तरह, बी '(0.5, 1) है। लेकिन ध्यान दें कि M का प्रक्षेपण (0, 1) है, जो A'B का मध्यबिंदु नहीं है। क्यों? क्योंकि खंड का दायाँ भाग बाएँ आधे की तुलना में कैमरे से बहुत दूर है, इसलिए यह छोटा दिखता है।

तो क्या होता है यदि आप रैखिक प्रक्षेप का उपयोग करते हुए Z की M की गणना करने का प्रयास करते हैं? dx = (0.5 - -1) = 1.5, dz = (4 - 2) = 2, इसलिए M 'जहाँ' X '= 0 के लिए, रैखिक रूप से प्रक्षेपित Z zA + (dz / dx) (x - xA) - 2 है + (2 / 1.5) (0 - -1) = 2 + 1.333 = 3.3333 - 3 नहीं!

क्यों? क्योंकि X 'दिशा में प्रत्येक चरण के लिए, आप Z दिशा में समान राशि को स्थानांतरित नहीं करते हैं (या, दूसरे शब्दों में, Z X का रैखिक कार्य नहीं है)। क्यों? क्योंकि जितना अधिक आप सही जाते हैं, कैमरा से दूर खंड उतना ही दूर होता है, इसलिए एक पिक्सेल अंतरिक्ष में लंबी दूरी का प्रतिनिधित्व करता है।

अंत में, यदि आप इसके बजाय 1 / Z प्रक्षेप करते हैं तो क्या होता है? पहले आप A और B पर क्रमशः 0.5 और 0.25 पर 1 / Z की गणना करते हैं। फिर आप प्रक्षेप करते हैं: dx = (0.5 - -1) = 1.5, dz = (0.25 - 0.5) = -0.25, इसलिए X '= 0 पर आप 1 / Z = 0.5 + (-0.25 / 1.5) * (0) की गणना करते हैं। -1) = 0.3333। लेकिन यह 1 / Z है, इसलिए Z का मान है ... बिल्कुल, 3. जैसा कि यह होना चाहिए।

हाँ, गणित बहुत बढ़िया है।


1
ओह, और "जब" के बारे में: त्रिकोण को शुरू करने से पहले 1 / जेड मानों की गणना करें (जैसे कि ऊर्ध्वाधर लूप से ठीक पहले), इसलिए आपको स्कैनलाइन के बाईं और दाईं ओर 1 / Z प्रक्षेपित किया जाता है। इन रैखिक रूप से प्रक्षेपित करें (फिर से 1 / जेड न करें - प्रक्षेपित मान पहले से ही 1 / Z हैं!), और zbuffer की जांच करने से पहले परिवर्तन को पूर्ववत करें।
ggambett

1
और अंत में, क्यों। एक विमान (जहां त्रिभुज एम्बेडेड है) Ax + By + Cz + D = 0. z स्पष्ट रूप से (x, y) का रैखिक कार्य करता है। आप इतना x '= x / z और y' = y / z प्रोजेक्ट करते हैं। वहां से, x = x'z और y = y'z। यदि आप इन्हें मूल समीकरण में बदल देते हैं तो आपको Ax'z + By'x + Cz + D = 0. अब z = -D / (Ax '+ By' + C) मिलता है, जहाँ यह स्पष्ट है कि z रैखिक कार्य नहीं है of (x ', y')। लेकिन 1 / z इसलिए (Ax '+ By' + C) / -D है, जो (x ', y') का एक रैखिक कार्य है।
20

1
आप जानते हैं, मैंने काफी लेख और पाठ्यक्रम पढ़े हैं, और उनमें से कोई भी आपके उत्तर के रूप में स्पष्ट नहीं थे। पोस्टरिटी के लिए, मैं यह भी ध्यान दूंगा कि "अक्षर" U "और" V "2 डी बनावट के अक्षों को निरूपित करते हैं क्योंकि" X "," Y "और" Z "मॉडल में 3 डी ऑब्जेक्ट के अक्षों को निरूपित करने के लिए पहले से ही उपयोग किए जाते हैं अंतरिक्ष। यूवी टेक्सचरिंग ऐसे पॉलीगॉन की अनुमति देता है जो एक 3D ऑब्जेक्ट को एक छवि से रंग के साथ चित्रित किया जाता है। " - विकिपीडिया - यूवी मैपिंग
स्पेक्ट्रलजम्प

जानकर ख़ुशी हुई की। मैंने वास्तव में, पिछले जीवन में कंप्यूटर ग्राफिक्स पढ़ाया था :)
ggambett

बहुत बहुत धन्यवाद - मैं हमेशा इस बारे में उत्सुक रहा हूँ - और मुझे नहीं पता कि क्या मुझे कभी बेहतर उत्तर मिला होता! +1
कोडस्मिथ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.