कई GLSL शेड्स के बीच कोड साझा करना


30

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

बेशक, यह भयानक अभ्यास है: अगर मुझे कहीं भी कोड बदलने की आवश्यकता है, तो मुझे यह सुनिश्चित करने की आवश्यकता है कि मैं इसे हर जगह बदल दूं।

क्या DRY रखने के लिए एक स्वीकृत सर्वोत्तम अभ्यास है ? क्या लोग केवल अपने सभी शेड्स के लिए एक ही आम फाइल तैयार करते हैं? क्या वे अपने स्वयं के अल्पविकसित सी-शैली पूर्वप्रक्रम लिखते हैं जो #includeनिर्देशों को पार्स करता है ? यदि उद्योग में स्वीकृत पैटर्न हैं, तो मैं उनका अनुसरण करना चाहूंगा।


4
यह प्रश्न थोड़ा विवादास्पद हो सकता है, क्योंकि कई अन्य एसई साइटें सर्वोत्तम प्रथाओं के बारे में सवाल नहीं चाहती हैं। यह देखना जानबूझकर है कि यह समुदाय इस तरह के सवालों के बारे में कैसे खड़ा है।
मार्टिन एंडर

2
हम्म, मुझे अच्छा लग रहा है। मैं कहता हूं कि हम अपने प्रश्नों में स्टैकऑवरफ्लो की तुलना में कुछ हद तक "व्यापक" / "अधिक सामान्य" हैं।
क्रिस का कहना है कि मोनिका

2
StackOverflow एक एक 'न हम पूछते जब तक आप करने के लिए' हमें पूछना 'किया जा रहा से चला गया करने के लिए है कृपया' बोर्ड।
insidesin

यदि यह ऑन-टॉपिकनेस निर्धारित करने के लिए है, तो संबंधित मेटा प्रश्न के बारे में कैसे?
एसएल बार्थ -

जवाबों:


18

एक दृष्टिकोण का एक गुच्छा है, लेकिन कोई भी सही नहीं है।

कोड glAttachShaderको मिलाते हुए उपयोग करके कोड साझा करना संभव है , लेकिन इससे संरचनात्मक घोषणाओं या #define-d स्थिरांक जैसी चीजों को साझा करना संभव नहीं है। यह कार्यों को साझा करने के लिए काम करता है।

कुछ लोग glShaderSourceआपके कोड से पहले आम परिभाषाओं को प्रस्तुत करने के तरीके के रूप में पारित स्ट्रिंग्स के सरणी का उपयोग करना पसंद करते हैं , लेकिन इसके कुछ नुकसान हैं:

  1. यह नियंत्रित करना कठिन है कि शेडर के भीतर से क्या शामिल किया जाना चाहिए (इसके लिए आपको एक अलग सिस्टम की आवश्यकता है।)
  2. इसका अर्थ यह है कि shader लेखक GLSL #versionमें निम्नलिखित कथन के कारण GLSL को निर्दिष्ट नहीं कर सकता है :

#Version निर्देश, कुछ और करने से पहले एक शेडर में होने चाहिए टिप्पणियों और सफेद स्थान को छोड़कर।

इस कथन के कारण, घोषणाओं glShaderSourceसे पहले पाठ को प्रस्तुत करने के लिए उपयोग नहीं किया जा सकता है #version। इसका मतलब है कि #versionलाइन को आपके glShaderSourceतर्कों में शामिल करने की आवश्यकता है , जिसका अर्थ है कि आपके GLSL संकलक इंटरफ़ेस को किसी तरह से यह बताने की आवश्यकता है कि GLSL के किस संस्करण का उपयोग किए जाने की उम्मीद है। इसके अतिरिक्त, निर्दिष्ट नहीं करना #versionGLSL संस्करण 1.10 का उपयोग करने के लिए GLSL संकलक को डिफ़ॉल्ट बना देगा। यदि आप shader लेखकों #versionको स्क्रिप्ट को एक मानक तरीके से निर्दिष्ट करने देना चाहते हैं , तो आपको किसी तरह कथन के #includeबाद सम्मिलित करना होगा #version। यह स्पष्ट रूप से #versionस्ट्रिंग को खोजने के लिए GLSL shader को पार्स करके किया जा सकता है (यदि वर्तमान में) और इसके बाद अपना समावेश करें, लेकिन इसमें एक्सेस होने के बाद#includeनिर्देश आसानी से नियंत्रित करने के लिए बेहतर हो सकता है जब उन निष्कर्षों को बनाने की आवश्यकता होती है। दूसरी ओर, चूंकि जीएलएसएल #versionलाइन से पहले टिप्पणियों को अनदेखा करता है , आप अपनी फ़ाइल के शीर्ष पर टिप्पणियों के भीतर मेटाडेटा शामिल कर सकते हैं (yuck।)

अब सवाल यह है: क्या #includeआपके पास अपने पूर्वप्रोसेसर एक्सटेंशन को रोल करने के लिए एक मानक समाधान है या क्या आपको इसकी आवश्यकता है?

नहीं है GL_ARB_shading_language_includeविस्तार, लेकिन यह कुछ कमियां भी हैं:

  1. यह केवल NVIDIA ( http://delphigl.de/glcapsviewer/listreports2.php?listreportsbyextension=GL_ARB_shading_language_include ) द्वारा समर्थित है
  2. यह समय से पहले शामिल स्ट्रिंग्स को निर्दिष्ट करके काम करता है। इसलिए, संकलन करने से पहले, आपको यह निर्दिष्ट करने की आवश्यकता है कि स्ट्रिंग "/buffers.glsl"(जैसा कि उपयोग किया गया है #include "/buffers.glsl") फ़ाइल की सामग्री buffer.glsl(जो आपने लोड की है ) से मेल खाती है ।
  3. जैसा कि आपने बिंदु (2) में देखा होगा, आपके रास्तों को "/"लिनक्स शैली के निरपेक्ष पथों के साथ शुरू करने की आवश्यकता है । यह संकेतन आमतौर पर सी प्रोग्रामर्स के लिए अपरिचित है, और इसका मतलब है कि आप सापेक्ष पथ निर्दिष्ट नहीं कर सकते।

एक सामान्य डिज़ाइन अपने स्वयं के #includeतंत्र को लागू करने के लिए है, लेकिन यह मुश्किल हो सकता है क्योंकि आपको #ifसशर्त संकलन (जैसे हेडर गार्ड्स) को ठीक से संभालने के लिए अन्य पूर्वप्रक्रमक निर्देशों को पार्स (और मूल्यांकन) करने की आवश्यकता है ।

यदि आप अपना स्वयं का कार्यान्वयन करते हैं #include, तो आपके पास कुछ स्वतंत्रताएं हैं कि आप इसे कैसे लागू करना चाहते हैं:

  • आप समय से पहले तार को पास कर सकते हैं (जैसे GL_ARB_shading_language_include)।
  • आप इसमें शामिल कॉलबैक को निर्दिष्ट कर सकते हैं (यह डायरेक्टएक्स के डी 3 डी कम्पाइलर लाइब्रेरी द्वारा किया गया है।)
  • आप एक ऐसी प्रणाली लागू कर सकते हैं जो हमेशा फाइलसिस्टम से सीधे पढ़ती है, जैसा कि विशिष्ट सी अनुप्रयोगों में किया जाता है।

सरलीकरण के रूप में, आप स्वचालित रूप से अपनी प्रीप्रोसेसिंग परत में शामिल प्रत्येक के लिए हेडर गार्ड को सम्मिलित कर सकते हैं, इसलिए आपके प्रोसेसर की परत इस तरह दिखती है:

if (#include and not_included_yet) include_file();

(मुझे उपरोक्त तकनीक दिखाने का श्रेय ट्रेंट रीड को दिया जाता है।)

निष्कर्ष में , कोई स्वचालित, मानक और सरल समाधान मौजूद नहीं है। भविष्य के समाधान में, आप कुछ SPIR-V OpenGL इंटरफ़ेस का उपयोग कर सकते हैं, जिस स्थिति में GLSL से SPIR-V संकलक GL API से बाहर हो सकते हैं। OpenGL रनटाइम के बाहर कंपाइलर होने से चीजों को लागू करने में बहुत आसानी होती है #includeक्योंकि यह फाइलसिस्टम के साथ इंटरफेस करने के लिए अधिक उपयुक्त स्थान है। मेरा मानना ​​है कि मौजूदा व्यापक विधि सिर्फ एक कस्टम प्रीप्रोसेसर को लागू करना है जो किसी भी सी प्रोग्रामर से परिचित होना चाहिए।


चमक को ग्लिस्लाइज़ का उपयोग करके मॉड्यूल में भी अलग किया जा सकता है , हालांकि यह केवल नोड के साथ काम करता है।
एंडरसन ग्रीन

9

मैं आमतौर पर इस तथ्य का उपयोग करता हूं कि glShaderSource (...) स्ट्रिंग्स की एक सरणी को स्वीकार करता है क्योंकि यह इनपुट है।

मैं एक json- आधारित shader परिभाषा फ़ाइल का उपयोग करता हूं, जो निर्दिष्ट करती है कि एक shader (या अधिक सही होने के लिए कोई प्रोग्राम) कैसे बनाया गया है, और वहां मैं पूर्व-निर्धारित परिभाषित करता हूं कि मुझे आवश्यकता हो सकती है, यह उपयोग करने वाली वर्दी, वर्टेक्स / टुकड़ा shaders फ़ाइल, और सभी अतिरिक्त "निर्भरता" फाइलें। ये केवल उन कार्यों का संग्रह है जो वास्तविक shader स्रोत से पहले स्रोत से जुड़ जाते हैं।

बस जोड़ने के लिए, AFAIK, अवास्तविक इंजन 4 एक #include निर्देश का उपयोग करता है जो संकलित हो जाता है और संकलन से पहले सभी प्रासंगिक फाइलों को जोड़ देता है, जैसा कि आप सुझाव दे रहे थे।


4

मुझे नहीं लगता कि एक आम सम्मेलन है, लेकिन अगर मैं एक अनुमान लगाऊं, तो मैं कहूंगा कि लगभग हर कोई पाठ के समावेश के कुछ सरल रूप को प्रीप्रोसेसिंग चरण (एक #includeएक्सटेंशन) के रूप में लागू करता है, क्योंकि यह करना बहुत आसान है इसलिए। (जावास्क्रिप्ट / वेबजीएल में, आप उदाहरण के लिए एक साधारण नियमित अभिव्यक्ति के साथ ऐसा कर सकते हैं)। इसका उल्टा यह है कि आप "रिलीज़" बिल्ड के लिए एक ऑफ़लाइन चरण में प्रीप्रोसेसिंग का प्रदर्शन कर सकते हैं, जब shader कोड को अब बदलने की आवश्यकता नहीं है।

वास्तव में, एक संकेत है कि यह दृष्टिकोण आम है तथ्य यह है कि उसके लिए एक एआरबी विस्तार पेश किया गया था GL_ARB_shading_language_include:। मुझे यकीन नहीं है कि अब तक यह एक मुख्य विशेषता बन गई है या नहीं, लेकिन विस्तार ओपन 2 जी के खिलाफ लिखा गया था।


2
GL_ARB_shading_language_include एक मुख्य विशेषता नहीं है। वास्तव में, केवल NVIDIA ही इसका समर्थन करता है। ( delphigl.de/glcapsviewer/… )
निकोलस लुई

4

कुछ लोगों ने पहले ही इंगित किया है कि glShaderSourceस्ट्रिंग्स की एक सरणी ले सकते हैं।

उसके ऊपर, GLSL में संकलन ( glShaderSource,glCompileShader में shader का ) और लिंकिंग ( glAttachShader, glLinkProgram) अलग है।

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

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

अंत में यह तकनीक कुछ DRY मुद्दों को संबोधित करती है, लेकिन यह आदर्श से बहुत दूर है।

एक पक्ष विषय पर, मुझे यकीन नहीं है कि इस दृष्टिकोण का संकलन समय के संदर्भ में कोई प्रभाव पड़ता है; मैंने पढ़ा है कि कुछ ड्राइवर केवल जोड़ने पर shader प्रोग्राम को संकलित करते हैं, लेकिन मैंने मापा नहीं है।


मेरी समझ से, मुझे लगता है कि यह संरचनात्मक परिभाषाओं को साझा करने की समस्या को हल नहीं करता है।
निकोलस लुई गुइल्मोट

@NicolasLouisGuillemot: हाँ आप सही हैं, केवल निर्देश कोड इस तरह से साझा किया जाता है, घोषणाएँ नहीं।
जुलिएन गुर्टाल्ट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.