2011-06-22 20 views
6

मैंने कई एंड्रॉइड ऐप्स लिखे हैं, लेकिन यह 3 डी प्रोग्रामिंग के साथ मेरा पहला अनुभव है।अप्रत्याशित रूप से काम कर रहे कमरे के अंदर प्रकाश स्रोत

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

संदर्भ के लिए, कमरा 14 इकाइयां चौड़ा है और 16 इकाइयां गहरी (मूल पर केंद्रित), 3 इकाइयां ऊंची (मूल से ऊपर 1 और नीचे 2) हैं। कमरे के बीच में 2 वस्तुएं हैं, एक घन और इसके ऊपर एक उल्टा पिरामिड है।

तब मैं घन और पिरामिड छाया करने के लिए एक प्रकाश स्रोत जोड़ने गया। मैंने कुछ नेहे के बंदरगाहों के माध्यम से पढ़ा और पीछा किया था, इसलिए मैंने जो कुछ भी प्रकाश में पाठ में काम किया था और इसे मेरे नए कोड पर लागू किया।

gl.glEnable(GL10.GL_LIGHTING); 
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, new float[] { 0.1f, 0.1f, 0.1f, 1f }, 0); 
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, new float[] { 1f, 1f, 1f, 1f }, 0); 
gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, new float[] { -4f, 0.9f, 6f, 1f }, 0); 
gl.glEnable(GL10.GL_LIGHT0); 

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

यहां क्या हो रहा है? मैंने प्रकाश पर कई लेख पढ़े और यह कैसे काम करता है, लेकिन मैंने यह इंगित करने के लिए कुछ भी नहीं देखा है कि यह कमरे के सभी किनारों को क्यों प्रकाश नहीं देगा, घन और पिरामिड प्रकाश की स्थिति के आधार पर छायांकित होगा। क्या प्रकाश के कुछ अपेक्षित व्यवहार हैं क्योंकि यह कमरे के अंदर "अंदर" है? क्या मैं बस कुछ आसान याद कर रहा हूं क्योंकि मैं नया हूं?

उत्तर

8

हर वस्तु अपने 3 डी दुनिया में एक normal है। आप शायद अपनी सतहों के लिए मानदंड निर्दिष्ट करना भूल गए हैं। उन्हें निर्दिष्ट किए बिना, ओपनजीएल आपकी दुनिया में सभी वस्तुओं को उसी तरह प्रकाश देगा।

3 डी में सतह की सामान्य स्थिति प्राप्त करने के लिए आपको कम से कम तीन शीर्षकों की आवश्यकता होती है, जिसका अर्थ है कि यह कम से कम एक त्रिकोण है।

नमूना सामान:

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

// Top triangle, three points in 3D space. 
vertices = new float[] { 
    -1.0f, 1.0f, -1.0f, 
    1.0f, 1.0f, -1.0f, 
    0.0f, 1.0f, -1.0f, 
} 

इन तीन अंक को देखते हुए, अब आप का पालन करते हुए दो वैक्टर परिभाषित कर सकते हैं: अब जब

// Simple vector class, created by you. 
Vector3f vector1 = new Vector3f(); 
Vector3f vector2 = new Vector3f(); 

vector1.x = vertices[0] - vertices[3]; 
vector1.y = vertices[1] - vertices[4]; 
vector1.z = vertices[2] - vertices[5]; 

vector2.x = vertices[3] - vertices[6]; 
vector2.y = vertices[4] - vertices[7]; 
vector2.z = vertices[5] - vertices[8]; 

आपके पास दो वैक्टर हैं, आप अंततः Cross Product का उपयोग कर सतह की सामान्य स्थिति प्राप्त कर सकते हैं। संक्षेप में, क्रॉस उत्पाद एक ऑपरेशन होता है जिसके परिणामस्वरूप एक नया वेक्टर होता है जिसमें एक इनपुट होता है जो इनपुट वैक्टरों के लंबवत होता है। यह सामान्य है जिसे हमें चाहिए।

अपने कोड में क्रॉस उत्पाद प्राप्त करने के लिए आपको अपनी स्वयं की विधि लिखनी है जो इसकी गणना करता है।

एक एक्स बी = (- Az * करके, Az * Bx - - कुल्हाड़ी * Bz, कुल्हाड़ी * तक एय * Bx एय * Bz): सिद्धांत रूप में आप इस सूत्र दिया पार उत्पाद की गणना

कोड में (ऊपर वैक्टर का उपयोग करके):

public Vector3f crossProduct(Vector3f vector1, Vector3f vector2) { 
    Vector3f normalVector = new Vector3f(); 

    // Cross product. The normalVector contains the normal for the 
    // surface, which is perpendicular both to vector1 and vector2. 
    normalVector.x = vector1.y * vector2.z - vector1.z * vector2.y; 
    normalVector.y = vector1.z * vector2.x - vector1.x * vector2.z; 
    normalVector.z = vector1.x * vector2.y - vector1.y * vector2.x; 

    return normalVector; 
} 

किसी भी आगे की टिप्पणी से पहले; आप किसी सरणी में अपने मानक निर्दिष्ट कर सकते हैं और आवश्यकता होने पर उन्हें ओपनजीएल में डाल सकते हैं, लेकिन अगर आप इसमें खोदते हैं तो इस विषय की आपकी समझ बेहतर होगी और आपका कोड अधिक लचीला होगा।

तो अब हम एक सामान्य जो आप, के माध्यम से (NeHe के बंदरगाहों की तरह है, लेकिन गतिशील) अपने सामान्य सरणी के लिए वेक्टर मान निर्दिष्ट पाश और क्रम में GL_NORMAL_ARRAY उपयोग करने के लिए ओपन पाने के लिए ओपन सेट अप पर प्रकाश को प्रतिबिंबित करने के लिए कर सकते हैं ऑब्जेक्ट सही ढंग से:

gl.glEnableClientState(GL10.GL_NORMAL_ARRAY); 

// I'm assuming you know how to put it into a FloatBuffer. 
gl.glNormalPointer(GL10.GL_FLOAT, 0, mNormalsBuffer); 

// Draw your surface... 

एक और अंतिम टिप्पणी; यदि आप अन्य शिखर मानों (जैसे 5.0 एफ, 10.0 एफ या बड़े) का उपयोग कर रहे हैं तो आप normalize वेक्टर प्राप्त कर सकते हैं जो कुछ प्रदर्शन प्राप्त करने के लिए crossProduct() विधि से लौटाता है। अन्यथा ओपनजीएल को यूनिट वेक्टर प्राप्त करने के लिए नए वेक्टर की गणना करनी चाहिए और यह एक प्रदर्शन समस्या हो सकती है।

इसके अलावा, new float[] {-4f, 0.9f, 6f, 1f}GL_POSITION के लिए बिल्कुल सही नहीं है। जब चौथा मान 1.0f पर सेट होता है तो इसका मतलब है कि प्रकाश स्थिति 0, 0, 0 है, इससे कोई फर्क नहीं पड़ता कि पहले तीन मान क्या हैं। अपनी प्रकाश स्थिति के लिए वेक्टर निर्दिष्ट करने के लिए, चौथे मान को 0.0f पर बदलें।

+0

आह! ठीक है, मैंने नेहे के नमूने में glNormal3f को कॉल करने वाली लाइनों को याद रखा क्योंकि वह सभी आसान सतहों का उपयोग कर रहा था और जैसा कि आपने दिखाया है उन्हें गणना करने की आवश्यकता नहीं थी। चूंकि मैंने कमरे को स्ट्रिप्स और प्रशंसकों से पूरी तरह से बाहर कर दिया है, इसलिए मुझे परीक्षण करने से पहले कुछ सामान्यीकृत करने की आवश्यकता होगी। मैं मानदंडों की गणना पर विस्तृत स्पष्टीकरण की सराहना करता हूं। – atheaos

+0

बहुत बढ़िया जवाब! – Tak

1

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

+0

दिलचस्प, एक चलती हुई कैमरे के साथ प्रकाश पर प्रकाश में पढ़ने वाली कोई भी जानकारी, इसलिए उन्होंने यह नहीं बताया कि स्थिति को आंदोलन के साथ अद्यतन करने की आवश्यकता है। – atheaos