ओपनजीएल जानें। पाठ 6.3 - छवि आधारित प्रकाश व्यवस्था। विक्षेपण

OGL3 छवि या IBL ( छवि आधारित प्रकाश ) के आधार पर प्रकाश व्यवस्था विश्लेषणात्मक प्रकाश स्रोतों ( पिछले पाठ में चर्चा की गई) के लिए लेखांकन के आधार पर प्रकाश व्यवस्था के तरीकों की एक श्रेणी है, लेकिन प्रबुद्ध वस्तुओं के पूरे वातावरण को एक निरंतर प्रकाश स्रोत के रूप में देखते हुए। सामान्य तौर पर, इस तरह के तरीकों का तकनीकी आधार पर्यावरण के एक घन मानचित्र को संसाधित करने में निहित है (वास्तविक दुनिया में तैयार किया गया है या तीन आयामी दृश्य के आधार पर बनाया गया है) ताकि मानचित्र में संग्रहीत डेटा को सीधे प्रकाश गणना में उपयोग किया जा सके: वास्तव में, घन मानचित्र के प्रत्येक टेक्सल को प्रकाश स्रोत माना जाता है । सामान्य तौर पर, यह आपको दृश्य में वैश्विक प्रकाश के प्रभाव को पकड़ने की अनुमति देता है, जो एक महत्वपूर्ण घटक है जो वर्तमान दृश्य के समग्र "टोन" को बताता है और प्रबुद्ध वस्तुओं को बेहतर "एम्बेडेड" होने में मदद करता है।

चूंकि IBL एल्गोरिदम एक निश्चित "वैश्विक" वातावरण से प्रकाश व्यवस्था को ध्यान में रखते हैं, इसलिए उनके परिणाम को पृष्ठभूमि प्रकाश व्यवस्था का एक अधिक सटीक अनुकरण या यहां तक ​​कि वैश्विक प्रकाश व्यवस्था का बहुत मोटा अनुमान माना जाता है। यह पहलू IBL तरीकों को PBR मॉडल में शामिल करने के मामले में दिलचस्प बनाता है, क्योंकि प्रकाश मॉडल में परिवेश प्रकाश का उपयोग करने से ऑब्जेक्ट अधिक शारीरिक रूप से सही दिखने की अनुमति देता है।

सामग्री
भाग 1. आरंभ करना

  1. ओपन
  2. खिड़की का निर्माण
  3. नमस्कार खिड़की
  4. नमस्ते त्रिकोण
  5. shaders
  6. बनावट
  7. परिवर्तन
  8. समन्वय प्रणाली
  9. कैमरा

भाग 2. बुनियादी प्रकाश

  1. रंग
  2. प्रकाश मूल बातें
  3. सामग्री
  4. बनावट के नक्शे
  5. प्रकाश स्रोत
  6. एकाधिक प्रकाश स्रोत

भाग 3। 3 डी मॉडल डाउनलोड करें

  1. लाइब्रेरी को मान लें
  2. मेष बहुभुज वर्ग
  3. 3 डी मॉडल वर्ग

भाग 4. उन्नत OpenGL सुविधाएँ

  1. गहराई परीक्षण
  2. स्टैंसिल परीक्षण
  3. रंग मिलाना
  4. क्लिपिंग चेहरे
  5. फ्रेम बफर
  6. घन कार्ड
  7. उन्नत डेटा हैंडलिंग
  8. उन्नत GLSL
  9. ज्यामितीय shader
  10. instancing
  11. चौरसाई

भाग 5. उन्नत प्रकाश

  1. उन्नत प्रकाश व्यवस्था। ब्लिन-फोंग मॉडल।
  2. गामा सुधार
  3. छाया कार्ड
  4. सर्वदिशात्मक छाया नक्शे
  5. सामान्य मानचित्रण
  6. लंबन मानचित्रण
  7. एचडीआर
  8. फूल
  9. आस्थगित प्रतिपादन
  10. SSAO

भाग 6. पीबीआर

  1. सिद्धांत
  2. विश्लेषणात्मक प्रकाश स्रोत
  3. IBL। विक्षेपण।
  4. IBL। मिरर एक्सपोज़र।


IBL के प्रभाव को पहले से वर्णित PBR प्रणाली में शामिल करने के लिए, हम परिचित प्रतिबिंब समीकरण पर लौटते हैं:

एल ( पी , मीटर जी एक ) = मैं एन टी एल मैं हूँ मैं टी एम जी एक ( कश्मीर आर एक पी मैं + कश्मीर रोंr एक सी डी एफ जी 4 ( एन एम जी सी डी टी एन )         ( omegai cdotn))Li(p, omegai)n cdot omegaid omegai


जैसा कि पहले बताया गया है, मुख्य लक्ष्य सभी आने वाली विकिरण दिशाओं के लिए अभिन्न की गणना करना है wi गोलार्द्ध से अधिक  पिछले पाठ में, अभिन्न की गणना बोझ नहीं थी, क्योंकि हम पहले से ही प्रकाश स्रोतों की संख्या को जानते थे, और इसलिए, प्रकाश घटना की उन सभी दिशाओं में जो उनके अनुरूप हैं। उसी समय, इंटीग्रल को एक स्नैप के साथ हल नहीं किया जा सकता है: किसी भी गिरने वाले वेक्टर wi पर्यावरण से गैर-शून्य ऊर्जा चमक ले जा सकता है। परिणामस्वरूप, निम्न आवश्यकताओं को पूरा करने के लिए आवश्यक विधि की व्यावहारिक प्रयोज्यता के लिए:
  • एक मनमाना दिशा वेक्टर के लिए दृश्य की ऊर्जा चमक प्राप्त करने के लिए आपको एक तरह से आने की आवश्यकता है wi ;
  • यह आवश्यक है कि अभिन्न का समाधान वास्तविक समय में हो सकता है।

खैर, पहला बिंदु खुद ही हल हो जाता है। एक समाधान का एक संकेत पहले ही यहां फिसल गया है: किसी दृश्य या पर्यावरण के विकिरण का प्रतिनिधित्व करने के तरीकों में से एक एक घन नक्शा है जो विशेष प्रसंस्करण से गुजरा है। इस तरह के नक्शे में प्रत्येक टेक्सल को एक अलग उत्सर्जन स्रोत माना जा सकता है। एक मनमाना वेक्टर के अनुसार इस तरह के नक्शे से नमूनाकरण करके wi हम आसानी से इस दिशा में दृश्य की ऊर्जा चमक प्राप्त करते हैं।

तो, हम एक मनमाना वेक्टर के लिए दृश्य की ऊर्जा चमक प्राप्त करते हैं wi :

vec3 radiance = texture(_cubemapEnvironment, w_i).rgb; 

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

Lo(p, omegao)= int limit Omega(kd fracc pi+ks fracDFG4( nomegao cdotn)( omegai cdotn))Li(p, omegai)n cdot omegaid omegai



यह देखा जा सकता है कि डिफ्यूज़ से संबंधित अभिव्यक्ति के हिस्से kd और दर्पण ks BRDF घटक स्वतंत्र हैं। आप अभिन्न को दो भागों में विभाजित कर सकते हैं:

L_o (p, \ omega_o) = \ int \ limit _ {\ _ Omega} (k_d_ frac {c} {\ pi}) L_i (p, \ omega_i) n \ _ \ _ \ _ ओमेगा_आई + \ _ \ _ \ _ {ओमेगा} (k_s \ frac {DFG} {4 (\ omega_o \ cdot n) (\ omega_i \ cdot n)}) L_i (p, \ omega_i) n \ cdot \ omega_i d \ omega_i



भागों में ऐसा विभाजन हमें उनमें से प्रत्येक के साथ व्यक्तिगत रूप से निपटने की अनुमति देगा, और इस पाठ में हम फैलाने वाले प्रकाश के लिए जिम्मेदार भाग से निपटेंगे।

फैलाना घटक पर अभिन्न के रूप का विश्लेषण करने के बाद, हम यह निष्कर्ष निकाल सकते हैं कि लैम्बर्ट फैलाना घटक अनिवार्य रूप से एक स्थिर (रंग) है अपवर्तनांक kd और  pi एकीकृत की शर्तों के तहत स्थिर हैं) और अन्य चर पर निर्भर नहीं करता है। इस तथ्य को देखते हुए, हम अभिन्न को अभिन्न के संकेत से परे रख सकते हैं:

L_o (p, \ omega_o) = k_d \ frac {c} {\ pi} \ int \ limit \ _ \ _ Omega} L_i (p, \ omega_i) n \ cdot के omega_i d \ omega_i



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

कन्वेंशन डेटा सेट में प्रत्येक तत्व के लिए कुछ गणना लागू करने का ऑपरेशन है, सेट में अन्य सभी तत्वों के डेटा को ध्यान में रखते हुए। इस मामले में, ऐसा डेटा दृश्य या पर्यावरण मानचित्र की ऊर्जा चमक है। इस प्रकार, क्यूबिक मानचित्र में नमूने के प्रत्येक दिशा में एक मूल्य की गणना करने के लिए, हमें नमूना बिंदु के आसपास झूठ बोलने वाले गोलार्ध में नमूना के अन्य सभी संभावित दिशाओं से लिए गए मूल्यों को ध्यान में रखना होगा।

पर्यावरण मानचित्र को समझाने के लिए, आपको नमूने के प्रत्येक परिणामी दिशा के लिए अभिन्न को हल करने की आवश्यकता है wo दिशाओं के साथ कई असतत नमूने प्रदर्शन करके wi गोलार्ध से संबंधित   , और कुल ऊर्जा चमक का औसत। गोलार्ध, जिसके आधार पर नमूना लेने के निर्देश दिए गए हैं wi वेक्टर के साथ उन्मुख wo गंतव्य दिशा का प्रतिनिधित्व करना जिसके लिए वर्तमान दृढ़ संकल्प की गणना की जा रही है। एक बेहतर समझ के लिए चित्र को देखें:



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

इसलिए, यह कार्ड प्रत्येक टेक्सेल (दिशा के अनुरूप) में कनविक्शन परिणाम को संग्रहीत करता है wo ), और बाहरी रूप से ऐसा नक्शा पर्यावरण के नक्शे के औसत रंग को संग्रहीत करने जैसा दिखता है। ऐसे नक्शे से किसी भी दिशा में एक नमूना इस दिशा से निकलने वाले विकिरण के मूल्य को लौटा देगा।

पीबीआर और एचडीआर


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

तो, पीबीआर और एचडीआर हमेशा के लिए दोस्त हैं, यह समझ में आता है, लेकिन यह तथ्य छवि-आधारित प्रकाश विधियों से कैसे संबंधित है? पिछले पाठ में, यह दिखाया गया था कि PBR को HDR रेंडरिंग रेंज में परिवर्तित करना आसान है। एक "लेकिन" रहता है: चूंकि पर्यावरण से अप्रत्यक्ष रोशनी पर्यावरण के एक घन मानचित्र पर आधारित है, इसलिए पर्यावरण के नक्शे में इस पृष्ठभूमि प्रकाश की एचडीआर विशेषताओं को संरक्षित करने के लिए एक तरीका आवश्यक है।

अब तक, हमने एलडीआर प्रारूप (जैसे स्काईबॉक्स ) में निर्मित पर्यावरण मानचित्रों का उपयोग किया है। हमने उनमें से रंग नमूना का उपयोग किया है जैसा कि यह है और यह वस्तुओं के प्रत्यक्ष छायांकन के लिए काफी स्वीकार्य है। और यह पूरी तरह से अनुपयुक्त है जब भौतिक रूप से विश्वसनीय माप के स्रोतों के रूप में पर्यावरण के नक्शे का उपयोग किया जाता है।

RGBE - HDR छवि प्रारूप


RGBE छवि फ़ाइल प्रारूप से परिचित हों। एक्सटेंशन " .hdr " के साथ फाइलें एक विस्तृत गतिशील रेंज के साथ छवियों को संग्रहीत करने के लिए उपयोग की जाती हैं, जो रंग त्रय के प्रत्येक तत्व के लिए एक बाइट और सामान्य घातांक के लिए एक और बाइट आवंटित करती हैं। प्रारूप आपको एलडीआर रेंज [0., 1.] से परे एक रंग तीव्रता रेंज के साथ घन पर्यावरण के नक्शे को संग्रहीत करने की अनुमति देता है। इसका मतलब यह है कि प्रकाश स्रोत अपनी वास्तविक तीव्रता को बनाए रख सकते हैं, इस तरह के पर्यावरण मानचित्र द्वारा प्रतिनिधित्व किया जा रहा है।

विभिन्न वास्तविक परिस्थितियों में शूट किए गए आरजीबीई प्रारूप में नेटवर्क के पास बहुत सारे मुक्त वातावरण के नक्शे हैं। यहाँ sIBL संग्रह साइट से एक उदाहरण है:


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

Stb_image.h में RGBE प्रारूप के लिए समर्थन


इस छवि प्रारूप को स्वयं डाउनलोड करने के लिए प्रारूप विनिर्देश के ज्ञान की आवश्यकता होती है, जो कठिन नहीं है, लेकिन अभी भी श्रमसाध्य है। सौभाग्य से हमारे लिए , stb_image.h इमेज लोडिंग लाइब्रेरी, जिसे एक हेडर फाइल में लागू किया गया है, आरजीबीई फाइल लोड करने का समर्थन करता है, फ्लोटिंग-पॉइंट नंबरों की एक सरणी लौटाता है - हमें अपने उद्देश्यों की क्या आवश्यकता है! अपनी परियोजना में एक पुस्तकालय जोड़ना, छवि डेटा लोड करना बेहद सरल है:

 #include "stb_image.h" [...] stbi_set_flip_vertically_on_load(true); int width, height, nrComponents; float *data = stbi_loadf("newport_loft.hdr", &width, &height, &nrComponents, 0); unsigned int hdrTexture; if (data) { glGenTextures(1, &hdrTexture); glBindTexture(GL_TEXTURE_2D, hdrTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); stbi_image_free(data); } else { std::cout << "Failed to load HDR image." << std::endl; } 

लायब्रेरी स्वचालित रूप से आंतरिक HDR प्रारूप से मूल्यों को नियमित रूप से वास्तविक 32-बिट संख्या में परिवर्तित करती है, डिफ़ॉल्ट रूप से तीन रंग चैनलों के साथ। यह एक सामान्य 2D फ्लोटिंग पॉइंट टेक्सचर में मूल HDR इमेज के डेटा को बचाने के लिए पर्याप्त है।

एक समान-कोण स्कैन को क्यूबिक मैप में परिवर्तित करें


समान रूप से आयताकार स्कैन का उपयोग पर्यावरण के नक्शे से सीधे नमूनों का चयन करने के लिए किया जा सकता है, हालांकि, इसके लिए महंगे गणितीय संचालन की आवश्यकता होगी, जबकि एक सामान्य घन मानचित्र से प्राप्त करना व्यावहारिक रूप से प्रदर्शन में मुक्त होगा। इन विचारों से यह ठीक है कि इस पाठ में हम एक समान आयताकार छवि को एक घन मानचित्र में परिवर्तित करेंगे, जो बाद में उपयोग किया जाएगा। हालांकि, त्रि-आयामी वेक्टर का उपयोग करते हुए समान रूप से आयताकार मानचित्र से प्रत्यक्ष नमूना विधि भी यहां दिखाई जाएगी, ताकि आप उस कार्य की विधि का चयन कर सकें जो आपको सूट करती है।

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

 #version 330 core layout (location = 0) in vec3 aPos; out vec3 localPos; uniform mat4 projection; uniform mat4 view; void main() { localPos = aPos; gl_Position = projection * view * vec4(localPos, 1.0); } 

टुकड़े टुकड़े में, हम क्यूब के प्रत्येक चेहरे को छाया करते हैं जैसे कि हम समान रूप से आयताकार नक्शे के साथ क्यूब को शीट के साथ धीरे से लपेटने की कोशिश कर रहे थे। ऐसा करने के लिए, टुकड़े को स्थानांतरित करने के लिए नमूना दिशा को लिया जाता है, जिसे विशेष त्रिकोणमितीय जादू द्वारा संसाधित किया जाता है, और अंततः, चयन को एक समान-आयताकार मानचित्र से बनाया जाता है जैसे कि यह वास्तव में एक घन मानचित्र था। चयन परिणाम सीधे क्यूब चेहरे के टुकड़े के रंग के रूप में सहेजा जाता है:

 #version 330 core out vec4 FragColor; in vec3 localPos; uniform sampler2D equirectangularMap; const vec2 invAtan = vec2(0.1591, 0.3183); vec2 SampleSphericalMap(vec3 v) { vec2 uv = vec2(atan(vz, vx), asin(vy)); uv *= invAtan; uv += 0.5; return uv; } void main() { // localPos   vec2 uv = SampleSphericalMap(normalize(localPos)); vec3 color = texture(equirectangularMap, uv).rgb; FragColor = vec4(color, 1.0); } 

यदि आप वास्तव में इस shader और एक संबद्ध HDR पर्यावरण मानचित्र के साथ एक घन आकर्षित करते हैं, तो आपको कुछ ऐसा मिलता है:


यानी यह देखा जा सकता है कि वास्तव में हमने एक घन पर एक आयताकार बनावट का अनुमान लगाया है। महान, लेकिन यह वास्तविक घन मानचित्र बनाने में हमारी मदद कैसे करेगा? इस कार्य को समाप्त करने के लिए, एक ही क्यूब को 6 बार प्रस्तुत करना आवश्यक होता है, जिसमें कैमरा एक-एक चेहरे को देखता है, जबकि आउटपुट को एक अलग फ्रेम बफर ऑब्जेक्ट में लिखते हैं:

 unsigned int captureFBO, captureRBO; glGenFramebuffers(1, &captureFBO); glGenRenderbuffers(1, &captureRBO); glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, captureRBO); 

बेशक, हम भविष्य के घन मानचित्र के छह चेहरों में से प्रत्येक को संग्रहीत करने के लिए मेमोरी को व्यवस्थित करना नहीं भूलेंगे:

 unsigned int envCubemap; glGenTextures(1, &envCubemap); glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); for (unsigned int i = 0; i < 6; ++i) { //  ,     // 16     glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 512, 512, 0, GL_RGB, GL_FLOAT, nullptr); } glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 

इस तैयारी के बाद, यह केवल एक क्यूबिक मैप के कगार पर एक समान-आयताकार मानचित्र के कुछ हिस्सों के हस्तांतरण को सीधे करने के लिए रहता है।

हम बहुत अधिक विस्तार में नहीं जाएंगे, खासकर जब से कोड फ्रेम बफ़र और सर्वदिशात्मक छाया में पाठों में बहुत बार देखा जाता है । सिद्धांत रूप में, यह सभी घन के प्रत्येक चेहरे पर कैमरे को कड़ाई से उन्मुख करते हुए छह अलग-अलग दृश्य मैट्रिसेस तैयार करने के लिए नीचे आता है, साथ ही साथ क्यूब के पूरे चेहरे को पकड़ने के लिए 90 ° के कोण के साथ एक विशेष प्रक्षेपण मैट्रिक्स है। फिर, केवल छह बार, प्रतिपादन किया जाता है, और परिणाम एक फ़्लोटिंग-पॉइंट फ्रेमबफ़र में सहेजा जाता है:

 glm::mat4 captureProjection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f); glm::mat4 captureViews[] = { glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)), glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)), glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)), glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)), glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)), glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)) }; //  HDR        equirectangularToCubemapShader.use(); equirectangularToCubemapShader.setInt("equirectangularMap", 0); equirectangularToCubemapShader.setMat4("projection", captureProjection); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, hdrTexture); //         glViewport(0, 0, 512, 512); glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); for (unsigned int i = 0; i < 6; ++i) { equirectangularToCubemapShader.setMat4("view", captureViews[i]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, envCubemap, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderCube(); //    } glBindFramebuffer(GL_FRAMEBUFFER, 0); 

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

हम सबसे सरल स्काईबॉक्स शेडर स्केच करके परिणामी घन मानचित्र का परीक्षण करेंगे:

 #version 330 core layout (location = 0) in vec3 aPos; uniform mat4 projection; uniform mat4 view; out vec3 localPos; void main() { localPos = aPos; //         mat4 rotView = mat4(mat3(view)); vec4 clipPos = projection * rotView * vec4(localPos, 1.0); gl_Position = clipPos.xyww; } 

क्लिपपोस वेक्टर के घटकों के साथ चाल पर ध्यान दें : हम xyww tetrad का उपयोग करते हैं जब यह सुनिश्चित करने के लिए वर्टेक्स के रूपांतरित समन्वय को रिकॉर्ड किया जाता है कि स्काईबॉक्स के सभी टुकड़ों की अधिकतम गहराई 1.0 है (दृष्टिकोण इसी पाठ में पहले ही उपयोग किया गया था)। तुलना फ़ंक्शन को GL_LEQUAL में बदलना न भूलें:

 glDepthFunc(GL_LEQUAL); 

टुकड़ा shader बस एक घन मानचित्र से चयन करता है:

 #version 330 core out vec4 FragColor; in vec3 localPos; uniform samplerCube environmentMap; void main() { vec3 envColor = texture(environmentMap, localPos).rgb; envColor = envColor / (envColor + vec3(1.0)); envColor = pow(envColor, vec3(1.0/2.2)); FragColor = vec4(envColor, 1.0); } 

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

तो, प्राप्त स्काईबॉक्स को आउटपुट करते समय, पहले से ही परिचित क्षेत्रों के साथ, कुछ ऐसा ही प्राप्त होता है:


ठीक है, बहुत प्रयास किया गया था, लेकिन अंत में हमें सफलतापूर्वक एचडीआर पर्यावरण मानचित्र पढ़ने की आदत हो गई, इसे समबाहु से घन के नक्शे में परिवर्तित किया, और दृश्य में एक स्काईबॉक्स के रूप में एचडीआर घन मानचित्र का उत्पादन किया। इसके अलावा, एक घन मानचित्र के छह चेहरों को प्रस्तुत करके एक घन मानचित्र में परिवर्तित करने के लिए कोड हमारे लिए उपयोगी है एक पर्यावरण मानचित्र के दृढ़ संकल्प के कार्य में आगे। संपूर्ण रूपांतरण प्रक्रिया का कोड यहाँ है

क्यूबिक कार्ड का कॉन्फिडेंस


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

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

Lo(p,ωo)=kdcπΩLi(p,ωi)nωidωi



नतीजतन, किसी दिए गए मनमाना वेक्टर के लिए wi, हम इस दिशा में फैलता विकिरण प्राप्त करने के लिए गणना किए गए विकिरण नक्शे से नमूना कर सकते हैं। वर्तमान टुकड़े के बिंदु पर अप्रत्यक्ष विसरित विकिरण की भयावहता को निर्धारित करने के लिए, हम एक गोलार्ध उन्मुख से कुल विकिरण को सामान्य से टुकड़े की सतह तक ले जाते हैं। दूसरे शब्दों में, एक दृश्य के विकिरण को प्राप्त करना एक साधारण चयन के लिए आता है:

  vec3 irradiance = texture(irradianceMap, N); 

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


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

यह केवल एक और प्रसंस्करण shader लेने के लिए बनी हुई है:

 #version 330 core out vec4 FragColor; in vec3 localPos; uniform samplerCube environmentMap; const float PI = 3.14159265359; void main() { //       vec3 normal = normalize(localPos); vec3 irradiance = vec3(0.0); [...] //   FragColor = vec4(irradiance, 1.0); } 

यहां, एनवायरनमेंट सैम्पलर पर्यावरण का एक एचडीआर क्यूबिक मैप है जो पहले एक समबाहु से निकला है।

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

परावर्तन के लिए अभिव्यक्ति का अभिन्न अंग ठोस कोण पर निर्भर करता हैdw- ऐसे मान जिनके साथ काम करना बहुत सुविधाजनक नहीं है। बजाय एक ठोस कोण पर एकीकृत करने केdw हम गोलाकार निर्देशांक पर एकीकरण के लिए अग्रणी, अभिव्यक्ति को बदल देंगे θ और ϕ :


कोण Phi गोलार्ध के आधार के विमान में azimuth का प्रतिनिधित्व करेगा, 0 से भिन्न होगा 2π कोण θ ऊंचाई कोण का प्रतिनिधित्व करेगा, 0 से भिन्न 12π ऐसे शब्दों में प्रतिबिंबितता के लिए संशोधित अभिव्यक्ति निम्नानुसार है:

Lo(p,ϕo,θo)=kdcπ2πϕ=012πθ=0Li(p,ϕi,θi)cos(θ)sin(θ)dϕdθ



इस तरह के अभिन्न के समाधान के लिए गोलार्ध में नमूनों की एक सीमित संख्या लेने की आवश्यकता होगी Ωऔर परिणाम औसत। नमूनों की संख्या जानने के बादn1 और n2प्रत्येक गोलाकार निर्देशांक पर, हम रिनेमैनियन योग के अभिन्न अंग का अनुवाद कर सकते हैं :

Lo(p,ϕo,θo)=kdcπ1n1n2n1ϕ=0n2θ=0Li(p,ϕi,θi)cos(θ)sin(θ)dϕdθ


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

नतीजतन, कोड के रूप में प्रत्येक टुकड़े के लिए गोलाकार निर्देशांक के आधार पर गोलार्ध में असतत नमूने का कार्यान्वयन निम्नानुसार है:

 vec3 irradiance = vec3(0.0); vec3 up = vec3(0.0, 1.0, 0.0); vec3 right = cross(up, normal); up = cross(normal, right); float sampleDelta = 0.025; float nrSamples = 0.0; for(float phi = 0.0; phi < 2.0 * PI; phi += sampleDelta) { for(float theta = 0.0; theta < 0.5 * PI; theta += sampleDelta) { //   .   (  -) vec3 tangentSample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)); //      vec3 sampleVec = tangentSample.x * right + tangentSample.y * up + tangentSample.z * N; irradiance += texture(environmentMap, sampleVec).rgb * cos(theta) * sin(theta); nrSamples++; } } irradiance = PI * irradiance * (1.0 / float(nrSamples)); 

चर नमूनाडेल्टा गोलार्ध की सतह के साथ असतत कदम के आकार को निर्धारित करता है। इस मान को बदलकर, आप परिणाम की सटीकता को बढ़ा या घटा सकते हैं।

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

यह केवल उस कोड से निपटने के लिए बना हुआ है जो envCubemap पर्यावरण मानचित्र के दृढ़ीकरण के परिणामों को प्रस्तुत करता है और कैप्चर करता है सबसे पहले, मुख्य रेंडर चक्र में प्रवेश करने से पहले विकिरण को संग्रहीत करने के लिए एक घन मानचित्र बनाएं (आपको इसे एक बार करना होगा,):

 unsigned int irradianceMap; glGenTextures(1, &irradianceMap); glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap); for (unsigned int i = 0; i < 6; ++i) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 32, 32, 0, GL_RGB, GL_FLOAT, nullptr); } glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 

चूंकि विकिरण मानचित्र पर्यावरण के नक्शे की ऊर्जा चमक के समान रूप से वितरित नमूनों के औसत से प्राप्त होता है, इसलिए व्यावहारिक रूप से इसमें उच्च आवृत्ति वाले हिस्से और तत्व नहीं होते हैं - एक काफी छोटा रिज़ॉल्यूशन बनावट (32x32 यहां) और सक्षम रेखीय फ़िल्टरिंग इसे संग्रहीत करने के लिए पर्याप्त होगा।

अगला, इस रिज़ॉल्यूशन पर कैप्चर फ़्रेमबफ़र सेट करें:

 glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); glBindRenderbuffer(GL_RENDERBUFFER, captureRBO); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 32, 32); 

कन्वेंशन परिणामों को कैप्चर करने के लिए कोड एक समभुज से एक पर्यावरणीय मानचित्र को क्यूबिक वन में स्थानांतरित करने के लिए कोड के समान है, केवल एक कनवल्शनर शेड का उपयोग किया जाता है:

 irradianceShader.use(); irradianceShader.setInt("environmentMap", 0); irradianceShader.setMat4("projection", captureProjection); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); //        glViewport(0, 0, 32, 32); glBindFramebuffer(GL_FRAMEBUFFER, captureFBO); for (unsigned int i = 0; i < 6; ++i) { irradianceShader.setMat4("view", captureViews[i]); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradianceMap, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderCube(); } glBindFramebuffer(GL_FRAMEBUFFER, 0); 

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


यदि, परिणामस्वरूप, आपने कुछ ऐसा देखा, जो पर्यावरण के बहुत धुंधले नक्शे जैसा दिख रहा था, तो, सबसे अधिक संभावना है, दृढ़ संकल्प सफल रहा।

पीबीआर और अप्रत्यक्ष रोशनी


परिणामी विकिरण मानचित्र परावर्तित की विभाजित अभिव्यक्ति के फैलाना भाग में उपयोग किया जाता है और अप्रत्यक्ष रोशनी के सभी संभावित दिशाओं से संचित योगदान का प्रतिनिधित्व करता है। चूंकि इस मामले में प्रकाश विशिष्ट स्रोतों से नहीं आता है, लेकिन एक पूरे के रूप में पर्यावरण से, हम विसरित और दर्पण को अप्रत्यक्ष प्रकाश को पृष्ठभूमि ( परिवेश ) के रूप में मानते हैं , जो पहले उपयोग किए गए निरंतर मूल्य की जगह लेता है।

के साथ शुरू करने के लिए, एक विकिरण मानचित्र के साथ एक नया नमूना जोड़ने के लिए मत भूलना:

 uniform samplerCube irradianceMap; 

एक विकिरण मानचित्र होने से दृश्य और सामान्य से अप्रत्यक्ष फैलने वाली विकिरण के बारे में सारी जानकारी स्टोर हो जाती है, किसी विशेष टुकड़े के विकिरण पर डेटा प्राप्त करना उतना ही सरल है जितना कि बनावट से एक नमूना बनाना:

 // vec3 ambient = vec3(0.03); vec3 ambient = texture(irradianceMap, N).rgb; 

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

 vec3 kS = fresnelSchlick(max(dot(N, V), 0.0), F0); vec3 kD = 1.0 - kS; vec3 irradiance = texture(irradianceMap, N).rgb; vec3 diffuse = irradiance * albedo; vec3 ambient = (kD * diffuse) * ao; 

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


हल करने के लिए इस उपद्रव अभिव्यक्ति Fremenlya-श्लिक में खुरदरापन की शुरूआत हो सकती है, प्रक्रिया का वर्णन किया सेबेस्तियन Lagarde की :

 vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) { return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0); } 

फ्रेस्नेल सेट की गणना करते समय सतह की खुरदरापन को देखते हुए, पृष्ठभूमि घटक की गणना करने के लिए कोड निम्न रूप लेता है:

 vec3 kS = fresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness); vec3 kD = 1.0 - kS; vec3 irradiance = texture(irradianceMap, N).rgb; vec3 diffuse = irradiance * albedo; vec3 ambient = (kD * diffuse) * ao; 

जैसा कि यह पता चला है, छवि-आधारित प्रकाश का उपयोग स्वाभाविक रूप से एक क्यूबिक मानचित्र से एक नमूने तक नीचे उबलता है। सभी कठिनाइयाँ मुख्य रूप से प्रारंभिक तैयारी और पर्यावरण मानचित्र को विकिरण मानचित्र में स्थानांतरित करने से जुड़ी हैं। अलग-अलग धातु और खुरदरापन के साथ गोलाकार की एक सरणी युक्त विश्लेषणात्मक प्रकाश स्रोतों

पर एक सबक से एक परिचित दृश्य लेना , और पर्यावरण से फैलाना पृष्ठभूमि प्रकाश को जोड़ना, आपको कुछ इस तरह मिलता है:


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

सबक के लिए पूर्ण स्रोत कोड यहाँ है।अगले पाठ में, हम अंततः चिंतनशीलता की दूसरी छमाही से निपटेंगे, जो अप्रत्यक्ष स्पेक्युलर लाइटिंग के लिए जिम्मेदार है। इस कदम के बाद, आप वास्तव में प्रकाश व्यवस्था में पीबीआर दृष्टिकोण की शक्ति महसूस करेंगे।

अतिरिक्त सामग्री



पुनश्च : हमारे पास तबादलों के समन्वय के लिए एक तार हैयदि आपको अनुवाद में मदद करने की गंभीर इच्छा है, तो आपका स्वागत है!

Source: https://habr.com/ru/post/hi426987/


All Articles