
परिचय
OSG के लिए विशिष्ट प्रोग्रामिंग तकनीकों के बारे में बोलते हुए
, पिछली बार जब हमने कॉलबैक तंत्र और इंजन में इसके कार्यान्वयन के बारे में बात की थी। यह संभावनाओं को देखने का समय है कि यह तंत्र तीन-आयामी दृश्य की सामग्री के प्रबंधन के लिए प्रदान करता है।
अगर हम ऑब्जेक्ट एनीमेशन के बारे में बात करते हैं, तो OSG डेवलपर को इसके कार्यान्वयन के लिए दो विकल्प प्रदान करता है:
- प्रक्रियात्मक एनीमेशन वस्तुओं और उनकी विशेषताओं के परिवर्तन के माध्यम से प्रोग्रामेटिक रूप से लागू किया गया
- एक 3D संपादक से एनीमेशन निर्यात करना और इसे एप्लिकेशन कोड से प्रबंधित करना
शुरू करने के लिए, पहली संभावना पर विचार करें, सबसे स्पष्ट के रूप में। हम दूसरे के बारे में थोड़ी देर बाद निश्चित रूप से बात करेंगे।
1. प्रक्रियात्मक मॉर्फिंग एनीमेशन
दृश्य ग्राफ को पीछे छोड़ते समय, OSG OpenGL पाइपलाइन में डेटा स्थानांतरित करता है, जो एक अलग थ्रेड में चलता है। इस धागे को प्रत्येक फ्रेम में अन्य प्रसंस्करण धागे के साथ सिंक्रनाइज़ किया जाना चाहिए। ऐसा करने में विफलता फ्रेम () विधि को ज्यामिति डेटा को संसाधित करने से पहले पूरा करने का कारण हो सकता है। यह अप्रत्याशित कार्यक्रम व्यवहार और दुर्घटनाओं को जन्म देगा। OSG इस समस्या के समाधान के लिए सेटटैविरेन्स () ऑसग: ऑब्जेक्ट क्लास की विधि के रूप में प्रस्तुत करता है, जो सभी दृश्य वस्तुओं के लिए आधार है। आप ऑब्जेक्ट के लिए तीन प्रोसेसिंग मोड सेट कर सकते हैं
- UNSPECIFIED (डिफ़ॉल्ट रूप से) - OSG स्वतंत्र रूप से ऑब्जेक्ट के प्रसंस्करण क्रम को निर्धारित करता है।
- STATIC - वस्तु अपरिवर्तनीय है और इसके प्रसंस्करण का क्रम महत्वपूर्ण नहीं है। उल्लेखनीय रूप से प्रतिपादन की गति।
- डायनामिक - प्रतिपादन की शुरुआत से पहले ऑब्जेक्ट को संसाधित किया जाना चाहिए।
यह सेटिंग किसी भी समय कॉल करके सेट की जा सकती है
node->setDataVariance( osg::Object::DYNAMIC );
आम तौर पर स्वीकृत अभ्यास ज्यामिति को "मक्खी पर" को संशोधित करना है, अर्थात्, वर्टिकल ज्यामिति को प्राप्त करना, प्रत्येक फ्रेम में वर्टीकल, रंग मानदंडों और टेक्सचर के निर्देशांक को बदलना। इस तकनीक को मॉर्फिंग एनीमेशन कहा जाता है। इस मामले में, ज्यामिति के प्रसंस्करण का क्रम निर्णायक है - ड्राइंग शुरू होने से पहले इसके सभी परिवर्तनों को पुनर्गणना किया जाना चाहिए। इस ट्रिक को स्पष्ट करने के लिए, हम रंगीन वर्गाकार उदाहरण को थोड़ा संशोधित करते हैं, इसके एक कोने को एक्स अक्ष के चारों ओर घूमने के लिए मजबूर करते हैं।
अनिमेष उदाहरणmain.h #ifndef MAIN_H #define MAIN_H #include <osg/Geometry> #include <osg/Geode> #include <osgViewer/Viewer> #endif
main.cpp #include "main.h"
हम एक अलग फ़ंक्शन में एक वर्ग बनाएंगे
osg::Geometry *createQuad() { osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; vertices->push_back( osg::Vec3(0.0f, 0.0f, 0.0f) ); vertices->push_back( osg::Vec3(1.0f, 0.0f, 0.0f) ); vertices->push_back( osg::Vec3(1.0f, 0.0f, 1.0f) ); vertices->push_back( osg::Vec3(0.0f, 0.0f, 1.0f) ); osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array; normals->push_back( osg::Vec3(0.0f, -1.0f, 0.0f) ); osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array; colors->push_back( osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f) ); colors->push_back( osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f) ); colors->push_back( osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f) ); colors->push_back( osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f) ); osg::ref_ptr<osg::Geometry> quad = new osg::Geometry; quad->setVertexArray(vertices.get()); quad->setNormalArray(normals.get()); quad->setNormalBinding(osg::Geometry::BIND_OVERALL); quad->setColorArray(colors.get()); quad->setColorBinding(osg::Geometry::BIND_PER_VERTEX); quad->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4)); return quad.release(); }
जिसका वर्णन, सिद्धांत रूप में, आवश्यक नहीं है, क्योंकि हमने इस तरह के कार्यों को बार-बार किया है। इस वर्ग के शीर्षों को संशोधित करने के लिए, हम डायनामिकक्वाड कॉलबैक क्लास लिखते हैं, जो इसे ओएसजी से प्राप्त होती है :: ड्रॉएबल :: अपडेटबैकबैक
class DynamicQuadCallback : public osg::Drawable::UpdateCallback { public: virtual void update(osg::NodeVisitor *, osg::Drawable *drawable); };
इसमें अपडेट () विधि को ओवरराइड करना
void DynamicQuadCallback::update(osg::NodeVisitor *, osg::Drawable *drawable) { osg::Geometry *quad = static_cast<osg::Geometry *>(drawable); if (!quad) return; osg::Vec3Array *vertices = static_cast<osg::Vec3Array *>(quad->getVertexArray()); if (!vertices) return; osg::Quat quat(osg::PI * 0.01, osg::X_AXIS); vertices->back() = quat * vertices->back(); quad->dirtyDisplayList(); quad->dirtyBound(); }
यहाँ हमें एक ज्यामिति वस्तु का सूचक मिलता है
osg::Geometry *quad = static_cast<osg::Geometry *>(drawable);
हम ज्यामिति से कोने की एक सूची (या इसके लिए एक सूचक) पढ़ते हैं
osg::Vec3Array *vertices = static_cast<osg::Vec3Array *>(quad->getVertexArray());
सरणी में अंतिम तत्व (अंतिम शीर्ष) प्राप्त करने के लिए, ओएस :: सरणी वर्ग पीछे () विधि प्रदान करता है। एक्स अक्ष के सापेक्ष शीर्ष के रोटेशन को करने के लिए, हम चतुर्धातुक का परिचय देते हैं
osg::Quat quat(osg::PI * 0.01, osg::X_AXIS);
यही है, हम एक क्वाटर्नियन सेट करते हैं जो 0.01 * पाई के कोण द्वारा एक्स अक्ष के चारों ओर एक रोटेशन को लागू करता है। वर्टेक्स के निर्देशांक को परिभाषित करने वाले एक वेक्टर द्वारा चतुर्धातुक को गुणा करके शीर्ष को घुमाएं
vertices->back() = quat * vertices->back();
अंतिम दो कॉल प्रदर्शन सूची और आयामी ज्यामिति को संशोधित ज्यामिति के लिए याद करते हैं
quad->dirtyDisplayList(); quad->dirtyBound();
मुख्य () फ़ंक्शन के शरीर में, हम एक वर्ग बनाते हैं, इसके लिए गतिशील ड्राइंग मोड सेट करते हैं, और ज्यामिति में एक कॉलबैक जोड़ते हैं
osg::Geometry *quad = createQuad(); quad->setDataVariance(osg::Object::DYNAMIC); quad->setUpdateCallback(new DynamicQuadCallback);
मैं मूल रूप से मूल नोड बनाने और दर्शक को लॉन्च करने के लिए छोड़ दूंगा, क्योंकि हमने पहले ही अलग-अलग तरीकों से कम से कम बीस बार ऐसा किया है। नतीजतन, हमारे पास सबसे सरल मॉर्फिंग एनीमेशन है

अब setDataVariance () कॉल को हटाने (टिप्पणी पर) का प्रयास करें। शायद हम इस मामले में कुछ भी अपराधी नहीं देखेंगे - डिफ़ॉल्ट रूप से, ओएसजी ज्यामिति डेटा को अपडेट करने के लिए स्वचालित रूप से यह निर्धारित करने की कोशिश करता है कि रेंडरिंग के साथ सिंक्रनाइज़ करने की कोशिश की जा रही है। फिर डायनामिक से स्टेटिक में मोड बदलने की कोशिश करें और यह देखा जाएगा कि इमेज सुचारू रूप से रेंडर नहीं होती है, ध्यान देने योग्य झटके के साथ, त्रुटियों और चेतावनियों जैसे कि कंसोल में डाल रहे हैं
Warning: detected OpenGL error 'invalid value' at after RenderBin::draw(..)
यदि आप गंदेDisplayList () विधि को निष्पादित नहीं करते हैं, तो OpenGL ज्यामिति में सभी परिवर्तनों को अनदेखा करेगा और प्रतिपादन के लिए वर्ग बनाने के लिए बहुत शुरुआत में बनाई गई प्रदर्शन सूची का उपयोग करेगा। यह कॉल हटाएं और आप देखेंगे कि कोई एनीमेशन नहीं है।
मैलाबाउंड () विधि को कॉल किए बिना, बाउंडिंग बॉक्स को पुनर्गणना नहीं किया जाएगा और ओएसजी गलत तरीके से अदृश्य चेहरों को ट्रिम कर देगा।
2. गति प्रक्षेप की अवधारणा
मान लीजिए कि स्टेशन A से स्टेशन B तक जाने वाली ट्रेन को यात्रा करने में 15 मिनट लगते हैं। कॉलबैक में ट्रेन की स्थिति को बदलकर हम इस स्थिति का अनुकरण कैसे कर सकते हैं? सबसे आसान तरीका है कि स्टेशन ए की स्थिति को समय 0 के साथ, और स्टेशन बी को 15 मिनट के साथ सहसंबंधित करें और इन समयों के बीच ट्रेन को समान रूप से आगे बढ़ाएं। इस सरल दृष्टिकोण को रैखिक प्रक्षेप कहा जाता है। रैखिक प्रक्षेप में, एक मध्यवर्ती बिंदु की स्थिति को निर्दिष्ट करने वाला एक वेक्टर सूत्र द्वारा वर्णित है
p = (1 - t) * p0 + t * p1
जहां p0 शुरुआती बिंदु है; पी 1 अंतिम बिंदु है; t एक पैरामीटर है जो 0 से 1 तक समान रूप से बदलता है। हालांकि, ट्रेन की गति बहुत अधिक जटिल है: यह स्टेशन A को छोड़ती है, गति करती है, फिर स्थिर गति से चलती है और फिर स्टेशन B पर रुक जाती है। ऐसी प्रक्रिया रैखिक प्रक्षेप का वर्णन करने में सक्षम नहीं है और यह अस्वाभाविक लगता है।
ओएसजी डेवलपर को ऑगनेमेशन लाइब्रेरी प्रदान करता है, जिसमें दृश्य वस्तुओं के संचलन को आसानी से चेतन करने के लिए उपयोग किए जाने वाले कई मानक प्रक्षेप एल्गोरिदम हैं। इनमें से प्रत्येक फ़ंक्शन में आमतौर पर दो तर्क होते हैं: पैरामीटर का प्रारंभिक मूल्य (आमतौर पर 0) और पैरामीटर का अंतिम मूल्य (आमतौर पर 1)। इन कार्यों को गति की शुरुआत (InMotion), गति के अंत (आउटमोशन) या गति के प्रारंभ और अंत (InOutMotion) पर लागू किया जा सकता है
आंदोलन का प्रकार | कक्षा में | कक्षा से बाहर | इन / आउट क्लास |
---|
रैखिक प्रक्षेप | LinearMotion | - | - |
द्विघात प्रक्षेप | InQuadMotion | OutQuadMotion | InOutQuadMotion |
घन प्रक्षेप | InCubicMotion | OutCubicMotion | InOutCubicMotion |
4-क्रम प्रक्षेप | InQuartMotion | OutQuartMotion | InOutQuartMotion |
उछाल प्रभाव इंटरपोल | InBounceMotion | OutBounceMotion | InOutBounceMotion |
लोचदार पलटाव प्रक्षेप | InElasticMotion | OutElasticMotion | InOutElasticMotion |
साइनसोइडल इंटरपोलेशन | InSineMotion | OutSineMotion | InOutSineMotion |
उलटा इंटरपोलेशन | InBackMotion | OutBackMotion | InOutBackMotion |
वृत्ताकार प्रक्षेप | InCircMotion | OutCircMotion | InOutCircMotion |
घातीय प्रक्षेप | InExpoMotion | OutExpoMotion | InOutExpoMotion |
किसी ऑब्जेक्ट के आंदोलन का एक रैखिक प्रक्षेप बनाने के लिए, हम इस कोड को लिखते हैं
osg::ref_ptr<osgAnimation::LinearMotion> motion = new osgAnimation::LinearMotion(0.0f, 1.0f);
3. परिवर्तन नोड्स का एनीमेशन
ग्राफिक अनुप्रयोगों में प्रक्षेपवक्र एनीमेशन सबसे सामान्य प्रकार का एनीमेशन है। इस तकनीक का उपयोग कार की गति, हवाई जहाज की उड़ान या कैमरे की गति को चेतन करने के लिए किया जा सकता है। प्रक्षेपवक्र को पूर्वनिर्धारित किया जाता है, समय में सभी बिंदुओं, घुमावों और पैमाने के बदलावों के साथ। जब सिमुलेशन चक्र शुरू होता है, तो वस्तु की स्थिति को प्रत्येक फ्रेम में पुनर्गणना की जाती है, स्थिति के लिए रैखिक प्रक्षेप और घुमाव के चतुर्भुज के लिए स्केलिंग और गोलाकार रैखिक प्रक्षेप का उपयोग किया जाता है। ऐसा करने के लिए, osg :: Quat class के slerp () आंतरिक विधि का उपयोग करें।
OSG समय-भिन्न पथ का वर्णन करने के लिए osg :: AnimationPath वर्ग प्रदान करता है। प्रक्षेपवक्र में कुछ बिंदुओं के अनुरूप नियंत्रण बिंदुओं को जोड़ने के लिए इस वर्ग सम्मिलित () की विधि का उपयोग किया जाता है। नियंत्रण बिंदु को ओएसजी :: एनिमेशनपथ :: कंट्रोलप्वाइंट क्लास द्वारा वर्णित किया गया है, जिसका निर्माण पैरामीटर पैरामीटर के रूप में स्थिति लेता है, और वैकल्पिक रूप से, ऑब्जेक्ट रोटेशन और स्केलिंग पैरामीटर। उदाहरण के लिए
osg::ref_ptr<osg::AnimationPath> path = new osg::AnimationPath; path->insert(t1, osg::AnimationPath::ControlPoint(pos1, rot1, scale1)); path->insert(t2, ...);
यहाँ t1, t2 सेकंड में समय के उदाहरण हैं; रोट 1, ऑगमेंट द्वारा वर्णित समय t1 पर रोटेशन पैरामीटर है। Quat quaternion।
सेटलूपमोड () विधि के माध्यम से एनीमेशन लूप को नियंत्रित करना संभव है। डिफ़ॉल्ट रूप से, LOOP मोड चालू है - एनीमेशन लगातार दोहराया जाएगा। अन्य संभावित मान: NO_LOOPING - एक बार एनीमेशन चलाएं और SWING - आगे और रिवर्स दिशाओं में आंदोलन को लूप करें।
सभी आरंभीकरण पूरा होने के बाद, हम osg :: एनिमेशनपथ ऑब्जेक्ट को ऑगस से जोड़ते हैं।
4. पथ के साथ आंदोलन के एनीमेशन का एक उदाहरण
अब हम बिंदु (0,0,0) पर केंद्र के साथ एक सर्कल में अपने सेसना को स्थानांतरित करेंगे। प्रक्षेपवक्र पर विमान की स्थिति की गणना प्रमुख फ्रेम के बीच स्थिति और अभिविन्यास को रैखिक रूप से प्रक्षेपित करके की जाएगी।
अनिमेष उदाहरणmain.h #ifndef MAIN_H #define MAIN_H #include <osg/AnimationPath> #include <osg/MatrixTransform> #include <osgDB/ReadFile> #include <osgViewer/Viewer> #endif
main.cpp #include "main.h"
हम इस कोड को एक अलग फ़ंक्शन में ले जाकर, विमान का प्रक्षेपवक्र बनाकर शुरू करते हैं
osg::AnimationPath *createAnimationPath(double radius, double time) { osg::ref_ptr<osg::AnimationPath> path = new osg::AnimationPath; path->setLoopMode(osg::AnimationPath::LOOP); unsigned int numSamples = 32; double delta_yaw = 2.0 * osg::PI / (static_cast<double>(numSamples) - 1.0); double delta_time = time / static_cast<double>(numSamples); for (unsigned int i = 0; i < numSamples; ++i) { double yaw = delta_yaw * i; osg::Vec3d pos(radius * sin(yaw), radius * cos(yaw), 0.0); osg::Quat rot(-yaw, osg::Z_AXIS); path->insert(delta_time * i, osg::AnimationPath::ControlPoint(pos, rot)); } return path.release(); }
मापदंडों के रूप में, फ़ंक्शन सर्कल की त्रिज्या लेता है जिसके साथ विमान चलता है और जिस समय के दौरान यह एक क्रांति करेगा। फ़ंक्शन के अंदर, एक प्रक्षेपवक्र ऑब्जेक्ट बनाएं और एनीमेशन लूपिंग मोड चालू करें
osg::ref_ptr<osg::AnimationPath> path = new osg::AnimationPath; path->setLoopMode(osg::AnimationPath::LOOP);
निम्नलिखित कोड
unsigned int numSamples = 32; double delta_yaw = 2.0 * osg::PI / (static_cast<double>(numSamples) - 1.0); double delta_time = time / static_cast<double>(numSamples);
प्रक्षेपवक्र के सन्निकटन मापदंडों की गणना करता है। हम पूरे प्रक्षेपवक्र को सीधे खंडों के अंकों में विभाजित करते हैं, और ऊर्ध्वाधर अक्ष (yaw) के डेल्टा के चारों ओर विमान के रोटेशन के कोण में परिवर्तन की गणना करते हैं और अनुभाग से अनुभाग में जाने पर समय डेल्टा में परिवर्तन होते हैं। अब आवश्यक नियंत्रण बिंदु बनाएं
for (unsigned int i = 0; i < numSamples; ++i) { double yaw = delta_yaw * i; osg::Vec3d pos(radius * sin(yaw), radius * cos(yaw), 0.0); osg::Quat rot(-yaw, osg::Z_AXIS); path->insert(delta_time * i, osg::AnimationPath::ControlPoint(pos, rot)); }
चक्र में, पहले से आखिरी तक प्रक्षेपवक्र के सभी खंडों को क्रमबद्ध किया जाता है। प्रत्येक नियंत्रण बिंदु को एक कोण कोण की विशेषता होती है
double yaw = delta_yaw * i;
अंतरिक्ष में विमान के द्रव्यमान के केंद्र की स्थिति
osg::Vec3d pos(radius * sin(yaw), radius * cos(yaw), 0.0);
विमान का वांछित वांछित कोण (ऊर्ध्वाधर अक्ष के सापेक्ष) का रोटेशन चतुर्धातुक द्वारा निर्धारित किया जाता है
osg::Quat rot(-yaw, osg::Z_AXIS);
और फिर पथ के नियंत्रण बिंदुओं की सूची में गणना किए गए मापदंडों को जोड़ें
path->insert(delta_time * i, osg::AnimationPath::ControlPoint(pos, rot));
मुख्य कार्यक्रम में, हम बूट समय पर विमान मॉडल फ़ाइल के नाम को इंगित करने की बारीकियों पर ध्यान देते हैं
osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("../data/cessna.osg.0,0,90.rot");
- फ़ाइल नाम में एक प्रत्यय ".0,0,90.rot" जोड़ा गया था। OSG में उपयोग की गई फ़ाइल से ज्यामिति को लोड करने का तंत्र आपको लोड करने के बाद मॉडल की प्रारंभिक स्थिति और अभिविन्यास को निर्दिष्ट करने की अनुमति देता है। इस मामले में, हम चाहते हैं कि लोड होने के बाद मॉडल को Z अक्ष के चारों ओर 90 डिग्री घुमाया जाए।
इसके बाद, रूट नोड बनाया जाता है, जो ट्रांसफ़ॉर्मेशन नोड है, और मॉडल ऑब्जेक्ट को चाइल्ड नोड के रूप में जोड़ा जाता है
osg::ref_ptr<osg::MatrixTransform> root = new osg::MatrixTransform; root->addChild(model.get());
अब createAnimationPath () फ़ंक्शन द्वारा बनाए गए पथ को जोड़कर एक प्रक्षेपवक्र एनीमेशन कॉलबैक बनाएं
osg::ref_ptr<osg::AnimationPathCallback> apcb = new osg::AnimationPathCallback; apcb->setAnimationPath(createAnimationPath(50.0, 6.0));
इस कॉलबैक को रूपांतरण नोड में संलग्न करें
root->setUpdateCallback(apcb.get());
दर्शक को आरंभिक और हमेशा की तरह लॉन्च किया जाता है।
osgViewer::Viewer viewer; viewer.setSceneData(root.get()); return viewer.run();
एक हवाई जहाज गति एनीमेशन प्राप्त करें

सोचिए आपको इस उदाहरण में कुछ भी अजीब नहीं लगा? पहले, उदाहरण के लिए, एक कार्यक्रम में जब एक बनावट को प्रस्तुत किया जाता है, तो आपने अंतरिक्ष में मॉडल की स्थिति में बदलाव प्राप्त करने के लिए परिवर्तन मैट्रिक्स को स्पष्ट रूप से बदल दिया है। यहां हम केवल एक रूपांतरण नोड बनाते हैं और कोड में कहीं भी कोई स्पष्ट मैट्रिक्स असाइनमेंट नहीं है।
रहस्य यह है कि विशेष ऑग :: एनिमेशनपैथ कॉलबैक वर्ग यह काम करता है। पथ पर ऑब्जेक्ट की वर्तमान स्थिति के अनुसार, यह परिवर्तन मैट्रिक्स की गणना करता है और स्वचालित रूप से इसे रूपांतरण नोड पर लागू करता है, जो इसे संलग्न है, डेवलपर को नियमित संचालन के एक गुच्छा से बचाता है।
यह ध्यान दिया जाना चाहिए कि अन्य प्रकार के नोड्स के लिए ओएसजी :: एनिमेशनपैथबैक को संलग्न करने से न केवल कोई प्रभाव नहीं पड़ेगा, बल्कि अपरिभाषित कार्यक्रम व्यवहार भी हो सकता है। यह याद रखना महत्वपूर्ण है कि यह कॉलबैक केवल परिवर्तन नोड्स को प्रभावित करता है।
5. सॉफ्टवेयर नियंत्रण एनीमेशन
ओएसजी :: एनिमेशनपैथ कॉलबैक कार्यक्रम के निष्पादन के दौरान एनीमेशन को नियंत्रित करने के तरीके प्रदान करता है।
- रीसेट () - एनीमेशन रीसेट करें और इसे पहले खेलें।
- सेटपॉज़ () - एनीमेशन को विराम देता है। एक पैरामीटर के रूप में एक तार्किक मान लेता है
- setTimeOffset () - एनीमेशन की शुरुआत से पहले समय ऑफसेट सेट करता है।
- setTimeMultiplier () - एनीमेशन के त्वरण / मंदी के लिए समय कारक सेट करता है।
उदाहरण के लिए, एनीमेशन को विराम और रीसेट से हटाने के लिए, हम ऐसे कोड को निष्पादित करते हैं
apcb->setPause(false); apcb->reset();
और दोहरे त्वरण के साथ कार्यक्रम शुरू करने के बाद चौथे चौथे से एनीमेशन शुरू करने के लिए, ऐसा कोड
apcb->setTimeOffset(4.0f); apcb->setTimeMultiplier(2.0f);
6. ओपनजीएल में प्रिमिटिव के प्रतिपादन का क्रम
OpenGL विभिन्न बफ़र्स में वर्टेक्स और आदिम डेटा संग्रहीत करता है, जैसे कि रंग बफर, एक गहराई बफर, एक स्टैंसिल बफर, और इसी तरह। इसके अलावा, वह पहले से ही अपनी पाइप लाइन को भेजे गए कोने और त्रिकोणीय चेहरे को अधिलेखित नहीं करता है। इसका मतलब यह है कि ओपनजीएल एक नई ज्यामिति बनाता है, भले ही मौजूदा ज्यामिति कैसे बनाई गई हो। इसका मतलब यह है कि जिस क्रम में प्राइमिटिव्स को रेंडरिंग पाइपलाइन को भेजा जाता है, वह अंतिम परिणाम को प्रभावित करता है जिसे हम स्क्रीन पर देखते हैं।
गहराई बफ़र डेटा के आधार पर, ओपनग्लास सही ढंग से अपारदर्शी वस्तुओं को आकर्षित करेगा, जो कि प्रेक्षक से उनकी दूरी के अनुसार पिक्सल्स को छाँटेगा। हालांकि, रंग मिश्रण तकनीक का उपयोग करते समय, उदाहरण के लिए, पारदर्शी और पारभासी वस्तुओं को लागू करते समय, रंग बफर को अपडेट करने के लिए एक विशेष ऑपरेशन किया जाएगा। अल्फा चैनल (चौथे रंग घटक) के मूल्य को ध्यान में रखते हुए, छवि के नए और पुराने पिक्सेल मिश्रित होते हैं। यह इस तथ्य की ओर जाता है कि पारभासी और अपारदर्शी किनारों का प्रतिपादन क्रम अंतिम परिणाम को प्रभावित करता है

आकृति में, बाईं ओर की स्थिति में, पहले अपारदर्शी और फिर पारदर्शी वस्तुओं को पाइपलाइन में भेजा गया, जिसके कारण रंगीन बफर में सही बदलाव और चेहरे का सही प्रदर्शन हुआ। सही स्थिति में, पहले पारदर्शी वस्तुओं को खींचा गया था, और फिर अपारदर्शी, जिसके कारण गलत प्रदर्शन हुआ।
ओएसआर के सेटरेंडरिंगहिंट () विधि :: स्टेटसेट वर्ग ओएसजी को नोड्स और ज्यामितीय वस्तुओं के आवश्यक प्रतिपादन आदेश को इंगित करता है, अगर यह स्पष्ट रूप से करने की आवश्यकता है। यह विधि केवल यह बताती है कि अनुवाद करते समय पारभासी चेहरों को ध्यान में रखा जाना चाहिए या नहीं, जिससे यह सुनिश्चित हो सके कि यदि दृश्य में पारभासी चेहरे हैं, तो अपारदर्शी और फिर पारदर्शी चेहरे पहले खींचे जाएंगे, जो पर्यवेक्षक से दूरी को ध्यान में रखते हैं। इंजन को सूचित करने के लिए कि यह नोड अपारदर्शी है, हम इस कोड का उपयोग करते हैं
node->getOrCreateStateSet()->setRenderingHint(osg::StateSet::OPAQUE_BIN);
या पारदर्शी किनारे होते हैं
node->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
7. पारभासी वस्तुओं के कार्यान्वयन का एक उदाहरण
आइए हम उपरोक्त सभी सैद्धांतिक परिचय को पारभासी वस्तु के कार्यान्वयन के ठोस उदाहरण के साथ समझने का प्रयास करें।
पारदर्शिता का उदाहरणmain.h #ifndef MAIN_H #define MAIN_H #include <osg/BlendFunc> #include <osg/Texture2D> #include <osg/Geometry> #include <osgDB/ReadFile> #include <osgViewer/Viewer> #endif
main.cpp #include "main.h" int main(int argc, char *argv[]) { (void) argc; (void) argv; osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; vertices->push_back( osg::Vec3(-0.5f, 0.0f, -0.5f) ); vertices->push_back( osg::Vec3( 0.5f, 0.0f, -0.5f) ); vertices->push_back( osg::Vec3( 0.5f, 0.0f, 0.5f) ); vertices->push_back( osg::Vec3(-0.5f, 0.0f, 0.5f) ); osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array; normals->push_back( osg::Vec3(0.0f, -1.0f, 0.0f) ); osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array; texcoords->push_back( osg::Vec2(0.0f, 0.0f) ); texcoords->push_back( osg::Vec2(0.0f, 1.0f) ); texcoords->push_back( osg::Vec2(1.0f, 1.0f) ); texcoords->push_back( osg::Vec2(1.0f, 0.0f) ); osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array; colors->push_back( osg::Vec4(1.0f, 1.0f, 1.0f, 0.5f) ); osg::ref_ptr<osg::Geometry> quad = new osg::Geometry; quad->setVertexArray(vertices.get()); quad->setNormalArray(normals.get()); quad->setNormalBinding(osg::Geometry::BIND_OVERALL); quad->setColorArray(colors.get()); quad->setColorBinding(osg::Geometry::BIND_OVERALL); quad->setTexCoordArray(0, texcoords.get()); quad->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4)); osg::ref_ptr<osg::Geode> geode = new osg::Geode; geode->addDrawable(quad.get()); osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D; osg::ref_ptr<osg::Image> image = osgDB::readImageFile("../data/Images/lz.rgb"); texture->setImage(image.get()); osg::ref_ptr<osg::BlendFunc> blendFunc = new osg::BlendFunc; blendFunc->setFunction(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); osg::StateSet *stateset = geode->getOrCreateStateSet(); stateset->setTextureAttributeAndModes(0, texture.get()); stateset->setAttributeAndModes(blendFunc); osg::ref_ptr<osg::Group> root = new osg::Group; root->addChild(geode.get()); root->addChild(osgDB::readNodeFile("../data/glider.osg")); osgViewer::Viewer viewer; viewer.setSceneData(root.get()); return viewer.run(); }
अधिकांश भाग के लिए, यहां दिखाए गए कोड में कुछ नया नहीं है: दो ज्यामितीय ऑब्जेक्ट बनाए गए हैं - एक बनावट वर्ग और एक हैंग ग्लाइडर, जिसका मॉडल एक फ़ाइल से लोड किया गया है। हालांकि, हम वर्ग के सभी कोने के लिए एक सफेद पारभासी रंग लागू करते हैं
colors->push_back( osg::Vec4(1.0f, 1.0f, 1.0f, 0.5f) );
- अल्फा चैनल मान 0.5 है, जो, बनावट के रंगों के साथ मिश्रित होने पर, एक पारभासी वस्तु का प्रभाव देना चाहिए। इसके अलावा, पारदर्शिता प्रसंस्करण के लिए रंग सम्मिश्रण समारोह निर्धारित किया जाना चाहिए।
osg::ref_ptr<osg::BlendFunc> blendFunc = new osg::BlendFunc; blendFunc->setFunction(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
इसे OpenGL स्टेट मशीन में पास करना
stateset->setAttributeAndModes(blendFunc);
इस कार्यक्रम को संकलित और चलाने के दौरान, हमें निम्नलिखित परिणाम मिलते हैं

इसे रोको! और पारदर्शिता कहाँ है? बात यह है कि हम इंजन को यह बताना भूल गए कि पारदर्शी किनारों को संसाधित किया जाना चाहिए, जिसे कॉल करके आसानी से हल किया जाता है
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
जिसके बाद हमें वह परिणाम मिलता है जो हमें चाहिए - हैंग ग्लाइडर विंग एक पारभासी बनावट वाले वर्ग के माध्यम से चमकता है

GL_SRC_ALPHA और GL_ONE_MINUS_SRC_ALPHA मिक्सिंग फ़ंक्शन के मापदंडों का मतलब है कि पारभासी चेहरे को खींचते समय परिणामी स्क्रीन पिक्सेल में सूत्र द्वारा गणना किए गए रंग घटक होंगे।
R = srcR * srcA + dstR * (1 - srcA) G = srcG * srcA + dstG * (1 - srcA) B = srcB * srcA + dstB * (1 - srcA)
जहां [srcR, srcG, srcB] वर्ग बनावट के रंग घटक हैं; [dstR, dstG, dstB] — , , . srcA - .
seRenderingHint() , , . , .
8.
. . , .
.
. , - , , 1 — . , 0 1 .
fading-inmain.h #ifndef MAIN_H #define MAIN_H #include <osg/Geode> #include <osg/Geometry> #include <osg/BlendFunc> #include <osg/Material> #include <osgAnimation/EaseMotion> #include <osgDB/ReadFile> #include <osgViewer/Viewer> #endif
main.cpp #include "main.h"
- -
class AlphaFadingCallback : public osg::StateAttributeCallback { public: AlphaFadingCallback() { _motion = new osgAnimation::InOutCubicMotion(0.0f, 1.0f); } virtual void operator() (osg::StateAttribute* , osg::NodeVisitor*); protected: osg::ref_ptr<osgAnimation::InOutCubicMotion> _motion; };
_motion , . , ,
AlphaFadingCallback() { _motion = new osgAnimation::InOutCubicMotion(0.0f, 1.0f); }

InOutCubicMotion 0 1. operator()
void AlphaFadingCallback::operator()(osg::StateAttribute *sa, osg::NodeVisitor *nv) { (void) nv; osg::Material *material = static_cast<osg::Material *>(sa); if (material) { _motion->update(0.0005f); float alpha = _motion->getValue(); material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0.0f, 1.0f, 1.0f, alpha)); } }
osg::Material *material = static_cast<osg::Material *>(sa);
callback , , , . — ,
_motion->update(0.0005f);
float alpha = _motion->getValue();
material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0.0f, 1.0f, 1.0f, alpha));
main(). , — OSG
osg::ref_ptr<osg::Drawable> quad = osg::createTexturedQuadGeometry( osg::Vec3(-0.5f, 0.0f, -0.5f), osg::Vec3(1.0f, 0.0f, 0.0f), osg::Vec3(0.0f, 0.0f, 1.0f));
, , . ,
osg::ref_ptr<osg::Material> material = new osg::Material; material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0.0f, 1.0f, 1.0f, 0.5f));
. Ambient color — , , . Diffuse color — , , , . FRONT_AND_BACK , , .
material->setUpdateCallback(new AlphaFadingCallback);
geode->getOrCreateStateSet()->setAttributeAndModes(material.get());
— ,
geode->getOrCreateStateSet()->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); geode->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
osg::ref_ptr<osg::Group> root = new osg::Group; root->addChild(geode.get()); root->addChild(osgDB::readNodeFile("../data/glider.osg")); osgViewer::Viewer viewer; viewer.setSceneData(root.get()); return viewer.run();

:
, . – main.h
#include <osgAnimation/EaseMotion>
OSG, , , , . osgAnimation/ , , ( )
LIBS += -losgAnimation
जारी रखने के लिए ...