सेमी-कॉमन अप्रोच यह है कि मैं जिसे shader घटकों को कॉल करता हूं , उसी के समान मुझे लगता है कि आप मॉड्यूल कह रहे हैं।
विचार पोस्ट-प्रोसेसिंग ग्राफ के समान है। आप shader कोड का हिस्सा लिखते हैं जिसमें आवश्यक इनपुट, जेनरेट किए गए आउटपुट और फिर वास्तव में उन पर काम करने के लिए कोड दोनों शामिल होते हैं। आपके पास एक सूची है जो दर्शाती है कि किसी भी स्थिति में आवेदन करने के लिए कौन सा शेड है (क्या इस सामग्री को एक बंप मैपिंग घटक की आवश्यकता है, चाहे स्थगित या आगे घटक सक्षम हो, आदि)।
अब आप इस ग्राफ को ले सकते हैं और इससे shader कोड तैयार कर सकते हैं। इसका अधिकतर अर्थ है कि 'चंक्स' कोड को जगह में चिपकाना, ग्राफ़ के साथ यह सुनिश्चित करना कि वे पहले से ही आवश्यक क्रम में हैं, और फिर shader निविष्टियाँ / आउटपुट में उपयुक्त के रूप में चिपकाने (GLSL में, इसका मतलब है कि आपके "वैश्विक" को परिभाषित करना) , बाहर, और समान चर)।
यह एक ubershader दृष्टिकोण के समान नहीं है। Ubershaders वे हैं जहाँ आपने shader के एक सेट में हर चीज के लिए आवश्यक सभी कोड डाल दिए हैं, शायद #ifdefs और वर्दी का उपयोग कर रहे हैं और उन्हें संकलित या चलाते समय सुविधाओं को चालू और बंद करना पसंद करते हैं। मैं व्यक्तिगत रूप से ubershader दृष्टिकोण को घृणा करता हूं, लेकिन कुछ बल्कि प्रभावशाली एएए इंजन उनका उपयोग करते हैं (विशेष रूप से क्रायटेक ध्यान में आता है)।
आप कई तरीकों से shader chunks को संभाल सकते हैं। सबसे उन्नत तरीका - और यदि आप GLSL, HLSL, और कन्सोल का समर्थन करने की योजना बनाते हैं - तो एक shader भाषा के लिए एक parser लिखना है (शायद HLSL / Cg या GLSL के करीब जितना आप अपने देवताओं के लिए अधिकतम "समझ" के लिए कर सकते हैं) ) जो तब स्रोत से स्रोत अनुवाद के लिए इस्तेमाल किया जा सकता है। एक अन्य तरीका यह है कि XML फ़ाइलों या जैसे जैसे, shader chunks को लपेटा जाए
<shader name="example" type="pixel">
<input name="color" type="float4" source="vertex" />
<output name="color" type="float4" target="output" index="0" />
<glsl><![CDATA[
output.color = vec4(input.color.r, 0, 0, 1);
]]></glsl>
</shader>
उस दृष्टिकोण के साथ ध्यान दें कि आप विभिन्न API के लिए कई कोड अनुभाग बना सकते हैं या यहां तक कि कोड सेक्शन का संस्करण भी बना सकते हैं (इसलिए आपके पास GLSL 1.20 संस्करण और GLSL 3.20 संस्करण हो सकता है)। आपका ग्राफ स्वचालित रूप से शेडर चंक्स को भी बाहर कर सकता है, जिसमें कोई संगत कोड खंड नहीं है, ताकि आप पुराने हार्डवेयर पर अर्ध-सुशोभित गिरावट प्राप्त कर सकें (इसलिए सामान्य मैपिंग जैसी कोई चीज या जो कुछ भी पुराने हार्डवेयर पर बाहर रखा गया है, जो प्रोग्रामर की आवश्यकता के बिना उसका समर्थन नहीं कर सकता है स्पष्ट जांच का एक गुच्छा करें)।
एक्सएमएल नमूना तब कुछ इसी तरह उत्पन्न हो सकता है (माफी अगर यह अमान्य GLSL है, तो मुझे उस एपीआई के अधीन होने में थोड़ी देर हो गई है):
layout (location=0) in vec4 input_color;
layout (location=0) out vec4 output_color;
struct Input {
vec4 color;
};
struct Output {
vec4 color;
}
void main() {
Input input;
input.color = input_color;
Output output;
// Source: example.shader
#line 5
output.color = vec4(input.color.r, 0, 0, 1);
output_color = output.color;
}
आप थोड़े होशियार हो सकते हैं और अधिक "कुशल" कोड उत्पन्न कर सकते हैं, लेकिन ईमानदारी से कोई भी छाया संकलक जो कुल बकवास नहीं है, आपके लिए उस उत्पन्न कोड से अतिरेक को दूर करने वाला है। हो सकता है कि नए GLSL आपको फ़ाइल का नाम #line
अभी भी कमांड्स में रखने दें, लेकिन मुझे पता है कि पुराने संस्करण बहुत कम हैं और इसका समर्थन नहीं करते हैं।
यदि आपके पास एक से अधिक विखंडू हैं, तो उनके इनपुट (जो कि पेड़ में पूर्वजों द्वारा दिए गए आउटपुट के रूप में नहीं दिए गए हैं) को इनपुट ब्लॉक में समाहित किया गया है, जैसा कि आउटपुट हैं, और कोड को केवल संक्षिप्त किया गया है। थोड़ा अतिरिक्त काम यह सुनिश्चित करने के लिए किया जाता है कि चरण मिलान (शीर्ष बनाम टुकड़ा) और उस शीर्ष विशेषता इनपुट लेआउट "बस काम"। इस दृष्टिकोण के साथ एक और अच्छा लाभ यह है कि आप स्पष्ट वर्दी और इनपुट विशेषता बाइंडिंग इंडेक्स लिख सकते हैं जो जीएलएसएल के पुराने संस्करणों में असमर्थित हैं और इन्हें आपकी shader जनरेशन / बाइंडिंग लाइब्रेरी में हैंडल करते हैं। इसी तरह आप अपने VBO को स्थापित करने में मेटाडेटा का उपयोग कर सकते हैं और glVertexAttribPointer
अनुकूलता सुनिश्चित करने के लिए कॉल कर सकते हैं और वह सब कुछ "बस काम करता है।"
दुर्भाग्य से इस तरह की कोई अच्छी क्रॉस-एपीआई लाइब्रेरी पहले से नहीं है। Cg थोड़े करीब आता है, लेकिन इसमें AMD कार्ड पर OpenGL के लिए बकवास समर्थन है और यदि आप किसी भी मूल कोड सुविधाओं का उपयोग करते हैं तो यह बहुत धीमी गति से हो सकता है। DirectX इफेक्ट्स फ्रेमवर्क भी काम करता है, लेकिन निश्चित रूप से HLSL के अलावा किसी भी भाषा के लिए शून्य समर्थन है। जीएलएसएल के लिए कुछ अधूरे / छोटी-छोटी लाइब्रेरी हैं जो डायरेक्टएक्स लाइब्रेरी की नकल करती हैं लेकिन उनके राज्य को देखते हुए पिछली बार जब मैंने चेक किया तो मैं सिर्फ अपना लिखूंगा।
Ubershader दृष्टिकोण का अर्थ है कुछ सुविधाओं के लिए "अच्छी तरह से ज्ञात" पूर्वप्रक्रमक निर्देशों को परिभाषित करना और फिर अलग-अलग कॉन्फ़िगरेशन के साथ अलग-अलग सामग्रियों के लिए पुन: जमा करना। उदाहरण के लिए, एक सामान्य मानचित्र के साथ किसी भी सामग्री के लिए जिसे आप परिभाषित कर सकते हैं USE_NORMAL_MAPPING=1
और फिर अपने पिक्सेल-स्टेज ubershader में बस:
#if USE_NORMAL_MAPPING
vec4 normal;
// all your normal mapping code
#else
vec4 normal = normalize(in_normal);
#endif
यहां एक बड़ी समस्या यह है कि प्रीक्लेम्ड एचएलएसएल के लिए इसे संभालना है, जहां आपको उपयोग में आने वाले सभी संयोजनों को पहले से निर्धारित करने की आवश्यकता है। जीएलएसएल के साथ भी आपको समान शेयर्स को पुनः प्राप्त / कैशिंग से बचने के लिए उपयोग में आने वाले सभी प्रीप्रोसेसर निर्देशों की एक कुंजी को ठीक से बनाने में सक्षम होने की आवश्यकता है। वर्दी का उपयोग करने से जटिलता कम हो सकती है लेकिन प्रीप्रोसेसर वर्दी के विपरीत अनुदेश गिनती कम नहीं होती है और अभी भी प्रदर्शन पर कुछ मामूली प्रभाव पड़ सकता है।
बस स्पष्ट होने के लिए, दोनों दृष्टिकोण (साथ ही सिर्फ मैन्युअल रूप से शेड के एक टन को लिखना) सभी एएए अंतरिक्ष में उपयोग किए जाते हैं। जो भी आपके लिए सबसे अच्छा काम करता है का उपयोग करें।