2011-08-28 25 views
5

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

पहली चीज़ जो मुझे वास्तव में जरूरी थी वह शेडर्स और कार्यक्रमों का उपयोग करने का एक आसान तरीका था। शेडर वर्ग का मेरा विचार यहां है।

class Shader 
{ 
public: 
    //create a shader with no source code 
    explicit Shader(GLenum shaderType); 
    //create a shader with source code and compile it 
    Shader(GLenum shaderType, const QString& sourceCode); 
    //create a shader from source file and compile it 
    Shader(GLenum shaderType, QFile& sourceFile); 
    ~Shader(); 

    //change the source code and recompile 
    void Source(QFile& sourceFile); 
    void Source(const QString& sourceCode); 

    GLuint get() const; //get the handle 

private: 
    //common part for creation in different constructors 
    void createShader(GLenum shaderType); 
    //compile 
    void compile(); 

private: 
    GLuint handle; 
}; 

यह स्पष्ट होना चाहिए कि विभिन्न कार्य क्या कर रहे हैं। प्रत्येक प्रासंगिक ओपनजीएल रूटीन को कॉल कर रहा है, त्रुटियों के लिए जांच करता है और किसी भी विफलता के मामले में अपवाद फेंकता है। कन्स्ट्रक्टर glCreateShader पर कॉल करता है। अब मुश्किल हिस्सा है। विनाशक को glDeleteShader(handle); पर कॉल करने की आवश्यकता है, लेकिन इस मामले में मुझे एक दुविधा है:

विकल्प 1: असाइनमेंट और प्रतिलिपि अक्षम करें। इसमें संदर्भ गिनती से बचने और नकारात्मक_पॉइंटर्स का उपयोग करने के लिए मजबूर होना पड़ता है ताकि वे इन्हें वैक्टर में रख सकें और सामान्य रूप से गुजर सकें।

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

Shader s1(GL_VERTEX_SHADER, QFile("MyVertexShader.vp")); 
Shader s2(s1); 
s2.Source(QFile("MyOtherVertexShader.vp")); 

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

प्रश्न 1: कृपया विकल्पों और वैकल्पिक रूप से संपूर्ण विचार पर टिप्पणी करें।
Q2: अगर मैं विकल्प 2 का चयन करने के लिए गए थे, मैं इसे अपने आप को लागू करने के लिए है या वहाँ बढ़ावा या क्यूटी में एक तैयार वर्ग जो मैं से निकाले जाते हैं या के एक सदस्य हो सकता था है और मैं एक मिलेगा करना मुफ्त संदर्भ गिनती?
Q3: आप सहमत हैं कि Shader एक अमूर्त वर्ग बनाने और तीन व्युत्पन्न वर्ग VertexShader, FragmentShader होने, और GeometryShader overkill हो सकता है?

अगर तुम मुझे एक मौजूदा सी ++ ओपन ढांचे का संदर्भ लेना चाहिए, यह बहुत अच्छी बात है (के बाद से मैं वास्तव में एक नहीं मिला है) लेकिन यह है कि वास्तव में मेरे सवालों का जवाब की तुलना में एक ओर टिप्पणी किया जाना चाहिए । यह भी ध्यान रखें कि मैंने दस्तावेज़ों में कहीं भी QGLShader क्लास देखा है, लेकिन यह स्पष्ट रूप से क्यूटी के मेरे संस्करण में मौजूद नहीं है और मेरे पास अभी अपग्रेड करने से बचने के मेरे कारण हैं।

अद्यतन

जवाब के लिए धन्यवाद। मैंने अंततः स्रोत कार्यों को हटाकर अपने शेडर वर्ग को अपरिवर्तनीय बनाने का फैसला किया। शेडर को सृजन में संकलित किया जाता है और इसमें कोई गैर-आधार सदस्य-कार्य नहीं होता है। इस प्रकार एक साधारण संदर्भ गिनती एक ही समय में मेरी सभी समस्याओं को हल करती है।

+2

एक सी ++ ओपन ढांचे आप (?) विज़ुअलाइज़ेशन लाइब्रेरी की जाँच हो सकता है के लिए। यह सभी मूलभूत बातों से लेकर एक मार्चिंग क्यूब्स ज्यामिति अल्गो तक सामान का एक टन प्रदान करता है। महान पुस्तकालय, कुछ जटिल लेकिन बहुत पूर्ण। http://www.visualizationlibrary.org – ssube

+0

@peachykeen: मैं डॉक्स के माध्यम से देख रहा हूँ - प्रभावशाली लग रहा है! आपका बहुत बहुत धन्यवाद! –

+0

लेखक भी अत्यंत संवेदनशील और सहायक है। विशेष रूप से खिड़की के साथ कुछ विषमताएं हैं, लेकिन यदि आपको कोई बग मिलती है और इसकी रिपोर्ट होती है, तो यह आमतौर पर सप्ताह के भीतर तय होती है (मेरे अनुभव में)। – ssube

उत्तर

3

मैं कहता हूँ उपयोग विकल्प 1: यह सब कुछ विकल्प 2 कर सकते हैं (स्मार्ट संकेत के माध्यम से) कर सकते हैं, जबकि विकल्प 2 तुम भी अविवेक लागत का भुगतान जब आप इसकी आवश्यकता नहीं है बनाता है। इसके शीर्ष पर, लिखना तर्कसंगत है।

इसी प्रकार मैंने एक सी एपीआई पर लपेटते समय हैंडल-बॉडी/पीआईएमपीएल का उपयोग करने पर विचार किया है, कार्यों को लौटने की अनुमति देने के लिए (सी हैंडल प्रकार की प्रतिलिपि की गारंटी नहीं दी गई थी, इसलिए इसके लिए संकेत आवश्यक था)। मैं std::unique_ptr<T> के बाद से यह के खिलाफ फैसला करता है गैर चल -> चल परिवर्तन (shared_ptr<T> के रूप में ज्यादा T copyable करता है)। तब से मैं अपने वर्गों को 'कसकर' चाल/कॉपी सेमेन्टिक्स रखने के लिए डिजाइन करता हूं।

आप जब यह तथापि वाक्य-शोर की बात आती है एक बिंदु है! Boost.Phoenix और lambdas जैसी चीजें मदद करते हैं। यदि/जब वे एक विकल्प नहीं कर रहे हैं, मैं एक अलगshared_shader या जो कुछ भी आवरण लेखन कहेंगे (आवरण आवरण?), समझ में आता है कम से कम पुस्तकालय स्तर कोड के लिए (जो मेरा मानना ​​है कि यहां मामला है)। मैं अग्रेषण कार्यों लिखने की उकताहट के साथ मदद के लिए किसी भी उपयोगिता का पता नहीं है।

मैं भी नहीं जानता कि बहुत जब यह shaders की बात आती है तो मुझे यकीन है कि मैं अपने पिछले सवाल का जवाब कर सकते हैं नहीं कर रहा हूँ। मैं एक वर्ग पदानुक्रम मतलब होता अगर अलग shaders की संख्या अक्सर बदलने के लिए उत्तरदायी थे बनाने लगता है। मुझे नहीं लगता कि यह मामला है; मैं भी है कि भले ही मामले के बाद से अपने स्तर पर कार्यान्वयन एक पहले से मौजूद एपीआई यह अगर/जब एक नया शेडर जोड़ा जाता है कि एपीआई को अग्रेषित करने कोड फिर से एक परेशानी का बहुत अधिक नहीं है लपेटकर है थे लगता है।


आप फीनिक्स सुंदरता का एक उदाहरण के लिए पूछ रहे हैं के बाद से।

मैं यह सोचते हैं मैं भिन्नता की जरूरत नहीं है क्या करना चाहते हैं क्या:

std::transform(begin, end, functor); 

बजाय:

std::for_each(begin, end, *arg1 = ref(functor)(*arg1)); 

यह अभी भी std::transform (स्पष्टता के लिए वांछनीय) उपयोग करना संभव है कुछ फीनिक्स सुविधाओं का उपयोग कर (construct IIRC) लेकिन यह है कि आवंटन का खर्च आएगा।

+0

@ आर्मेन यह सही है। दोनों प्रदान करने का विकल्प 1 + 2 सबसे शक्तिशाली (क्लाइंट-कोड वार) है लेकिन लागू करने के लिए सबसे महंगा है (लाइब्रेरी-कोड वार)। एक फीनिक्स उदाहरण जोड़ा गया। –

3

मैं पहले से ही इन विकल्पों का मूल्यांकन किया है, और मैं क्रियान्वित किया है शेडर वर्ग एक अलग तरीका है।

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

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

अंतिम बात यह है कि ShaderObject क्लास असाइनमेंट, ठीक है जब तक आप एक बनाया शेडर वस्तु रिसाव नहीं है स्रोत के मामले में, मैं tehere दो विकल्प लगता है:। स्रोत बदला जा सकता है और शेडर अमान्य हो, या शेडर बन गंदे और वास्तव में एक संकलन की आवश्यकता है।

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

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

संबंधित मुद्दे