OpenSceneGraphシヌングラフずスマヌトポむンタヌ

画像



はじめに



前の蚘事で、゜ヌスからOpenSceneGraphアセンブリを芋お、空の玫色の䞖界に灰色の平面がぶら䞋がっおいる基本的な䟋を曞いた。 私は同意したすが、あたり印象的ではありたせん。 ただし、前述したように、この小さな䟋では、このグラフィック゚ンゞンのベヌスずなる䞻芁な抂念がありたす。 それらをより詳现に怜蚎したしょう。 以䞋の資料では、Alexander BobkovのOSGに関するブログのむラストを䜿甚しおいたす著者がOSGに関する蚘述を攟棄したのは残念です。 この蚘事は、 OpenSceneGraph 3.0の資料ず䟋にも基づいおいたす。 初心者向けガむド



前の出版物は批刀を受けおいたず蚀わざるを埗たせんが、それには郚分的に同意したす-資料は蚀われずに出おきお、文脈から倖れたした。 カットの䞋でこの省略を修正しようずしたす。



1.シヌンずそのノヌドのグラフに぀いお簡単に説明したす



゚ンゞンの䞭心抂念は、いわゆるシヌングラフです フレヌムワヌク自䜓の名前にこだわったのは偶然ではありたせん-3次元シヌンの論理的および空間的衚珟を敎理できる階局ツリヌ構造です。 シヌングラフには、ルヌトノヌドず、関連する䞭間ノヌドずタヌミナルノヌドたたはノヌドが含たれたす。



䟋えば







このグラフは、家ずその䞭のテヌブルで構成されるシヌンを瀺しおいたす。 家には特定の幟䜕孊的衚珟があり、ルヌトノヌドルヌトに関連付けられた特定の基本座暙系に察しお空間内の特定の方法で配眮されたす。 テヌブルは、家に関連しお䜕らかの方法で配眮され、ルヌトノヌドに関連しお家ずずもに配眮されるゞオメトリによっおも蚘述されたす。 1぀のosg :: Nodeクラスから継承するため、共通のプロパティを持぀すべおのノヌドは、機胜的な目的に応じおタむプに分割されたす。



  1. グルヌプノヌドosg :: Group-すべおの䞭間ノヌドの基本クラスであり、他のノヌドをグルヌプに結合するように蚭蚈されおいたす
  2. 倉換ノヌドosg ::倉換ずその子孫-オブゞェクト座暙の倉換を蚘述するように蚭蚈されおいたす
  3. ゞオメトリックノヌドosg :: Geode-1぀以䞊のゞオメトリックオブゞェクトに関する情報を含むシヌングラフのタヌミナルリヌフノヌド。


OSGのシヌンオブゞェクトのゞオメトリは、オブゞェクトの独自のロヌカル座暙系で蚘述されたす。 このオブゞェクトずルヌトノヌドの間にある倉換ノヌドは、マトリックス座暙倉換を実装しお、ベヌス座暙系でのオブゞェクトの䜍眮を取埗したす。



ノヌドは倚くの重芁な機胜を実行したす。特に、オブゞェクトの衚瀺状態を保存したす。この状態は、このノヌドに関連付けられたサブグラフのみに圱響したす。 シヌングラフ内のノヌド、ノヌドの状態を倉曎できるむベントハンドラヌ、およびノヌ​​ドに関連付けられたサブグラフに、いく぀かのコヌルバックを関連付けるこずができたす。



画面䞊の最終結果の取埗に関連するシヌングラフ䞊のすべおのグロヌバル操䜜は、グラフを定期的に詳现に走査するこずにより、゚ンゞンによっお自動的に実行されたす。



前回怜蚎した䟋では、シヌンは単䞀のオブゞェクト、぀たりファむルからロヌドされた飛行機モデルで構成されおいたした。 はるか先を芋るず、このモデルはシヌングラフのリヌフノヌドであるず蚀えたす。 ゚ンゞンのグロヌバルなベヌス座暙系にしっかりず溶接されおいたす。



2. OSGメモリ管理



シヌングラフのノヌドには、シヌンオブゞェクトずその操䜜に関する倚くのデヌタが栌玍されるため、このデヌタを栌玍するには、動的に含むメモリを割り圓おる必芁がありたす。 この堎合、シヌングラフを操䜜するずき、たずえばノヌドの䞀郚を削陀するずき、グラフの削陀されたノヌドが凊理されなくなったこずを泚意深く監芖する必芁がありたす。 開発者がオブゞェクトぞのポむンタが既存のデヌタを参照し、削陀する必芁があるかを远跡するこずは非垞に困難であるため、このプロセスには垞に時間のかかるデバッグ゚ラヌが䌎いたす。 効果的なメモリ管理がなければ、セグメンテヌション゚ラヌずメモリリヌクが発生する可胜性が高くなりたす。



メモリ管理はOSGの重芁なタスクであり、そのコンセプトは2぀のポむントに基づいおいたす。



  1. メモリの割り圓おオブゞェクトを栌玍するために必芁なメモリ量の割り圓おを確保したす。

  2. メモリヌを解攟したす䞍芁な堎合は、割り圓おられたメモリヌをシステムに戻したす。



C、Java、Visual Basic .Netなどの倚くの最新のプログラミング蚀語は、いわゆるガベヌゞコレクタヌを䜿甚しお、割り圓おられたメモリを解攟したす。 C ++蚀語の抂念はそのようなアプロヌチを提䟛しおいたせんが、いわゆるスマヌトポむンタヌを䜿甚しお暡倣するこずができたす。



今日、C ++には「すぐに䜿える」ず呌ばれる歊噚庫にスマヌトポむンタヌがありたすC ++ 17暙準は既にいく぀かの叀いタむプのスマヌトポむンタヌの蚀語を取り陀くこずに成功しおいたすが、これは垞にそうではありたせん。 0.9ず番号付けされたOSGの公匏バヌゞョンの最初のものは2002幎に誕生し、最初の公匏リリヌスたでさらに3幎がありたした。 その時点では、C ++暙準はただスマヌトポむンタヌを提䟛しおいたせんでした。 歎史的な䜙談を1぀信じたずしおも、蚀語自䜓は苊劎しおいたした。 そのため、OSGに実装されおいる独自のスマヌトポむンタヌの圢の自転車の倖芳は、驚くこずではありたせん。 このメカニズムぱンゞンの構造に深く統合されおいるため、最初からその動䜜を理解するこずが絶察に必芁です。



3. osg :: ref_ptr <>およびosg ::参照クラス



OSGは、osg :: ref_ptr <>テンプレヌトクラスに基づいお独自のスマヌトポむンタヌメカニズムを提䟛し、自動ガベヌゞコレクションを実装したす。 OSGは、適切な操䜜のために、参照カりントが䜜成されるメモリブロックを管理するための別のosg :: Referencedクラスを提䟛したす。



osg :: ref_ptr <>クラスは、いく぀かの挔算子ずメ゜ッドを提䟛したす。





osg :: Referencedクラスは、ノヌド、ゞオメトリ、レンダリング状態、ステヌゞに配眮された他のオブゞェクトなど、シヌングラフのすべおの芁玠の基本クラスです。 したがっお、シヌンのルヌトノヌドを䜜成しお、osg :: Referencedクラスによっお提䟛されるすべおの機胜を間接的に継承したす。 したがっお、私たちのプログラムには発衚がありたす



osg::ref_ptr<osg::Node> root;
      
      





osg :: Referencedクラスには、割り圓おられたメモリブロックぞの参照甚の敎数カりンタヌが含たれおいたす。 このカりンタヌは、クラスコンストラクタヌでれロに初期化されたす。 osg :: ref_ptr <>オブゞェクトが䜜成されるず、1ず぀増加したす。 このポむンタヌは、このポむンタヌによっお蚘述されたオブゞェクトぞの参照が削陀されるずすぐに枛少したす。 オブゞェクトは、スマヌトポむンタヌが参照を停止するず自動的に砎棄されたす。



osg :: Referencedクラスには、3぀のパブリックメ゜ッドがありたす。





これらのメ゜ッドは、osg :: Referencedから掟生したすべおのクラスで䜿甚できたす。 ただし、リンクカりンタヌを手動で制埡するず予枬できない結果が生じる可胜性があるこずを芚えおおく必芁がありたす。



4. OSGがガベヌゞを収集する方法ずその理由



スマヌトポむンタヌずガベヌゞコレクションを䜿甚する理由はいく぀かありたす。





シヌングラフがルヌトノヌドずいく぀かのレベルの子ノヌドで構成されおいるず仮定したす。 ルヌトノヌドずすべおの子ノヌドがosg :: ref_ptr <>クラスを䜿甚しお管理されおいる堎合、アプリケヌションはルヌトノヌドぞのポむンタヌのみを远跡できたす。 このノヌドを削陀するず、すべおの子ノヌドが順次自動的に削陀されたす。







スマヌトポむンタヌは、ロヌカル倉数、グロヌバル倉数、クラスメンバヌずしお䜿甚でき、スマヌトポむンタヌが範囲倖になるず自動的に参照カりントを枛らしたす。



OSG開発者は、スマヌトポむンタヌをプロゞェクトで䜿甚するこずを匷くお勧めしたすが、泚意すべき基本的なポむントがいく぀かありたす。





 osg::ref_ptr<osg::Node> node = new osg::Node; //  osg::Node node; // 
      
      







 osg::Node *tmpNode = new osg::Node; //  ,  ... osg::ref_ptr<osg::Node> node = tmpNode; //         !
      
      











シヌングラフのサンプルグラフでは、Child 1.1ノヌドはそれ自䜓を指し、Child 2.2ノヌドはChild 1.2ノヌドも指したす。 このような皮類のリンクは、リンク数の誀った蚈算ずプログラムの䞍明確な動䜜に぀ながる可胜性がありたす。



5.管理察象オブゞェクトの远跡



OSGのスマヌトポむンタヌメカニズムの動䜜を説明するために、次の合成䟋を䜜成したす。



main.h



 #ifndef MAIN_H #define MAIN_H #include <osg/ref_ptr> #include <osg/Referenced> #include <iostream> #endif // MAIN_H
      
      





main.cpp



 #include "main.h" class MonitoringTarget : public osg::Referenced { public: MonitoringTarget(int id) : _id(id) { std::cout << "Constructing target " << _id << std::endl; } protected: virtual ~MonitoringTarget() { std::cout << "Dsetroying target " << _id << std::endl; } int _id; }; int main(int argc, char *argv[]) { (void) argc; (void) argv; osg::ref_ptr<MonitoringTarget> target = new MonitoringTarget(0); std::cout << "Referenced count before referring: " << target->referenceCount() << std::endl; osg::ref_ptr<MonitoringTarget> anotherTarget = target; std::cout << "Referenced count after referring: " << target->referenceCount() << std::endl; return 0; }
      
      





osg ::参照される子孫クラスを䜜成したす。これは、むンスタンスが䜜成されたこずを報告し、むンスタンスの䜜成時に決定された識別子を衚瀺するコンストラクタずデストラクタ以倖では䜕も行いたせん。 スマヌトポむンタヌメカニズムを䜿甚しおクラスのむンスタンスを䜜成する



 osg::ref_ptr<MonitoringTarget> target = new MonitoringTarget(0);
      
      





次に、タヌゲットオブゞェクトの参照カりンタヌを衚瀺したす



 std::cout << "Referenced count before referring: " << target->referenceCount() << std::endl;
      
      





その埌、新しいスマヌトポむンタヌを䜜成し、前のポむンタヌの倀を割り圓おたす



 osg::ref_ptr<MonitoringTarget> anotherTarget = target;
      
      





そしお再び参照カりンタヌを衚瀺したす



 std::cout << "Referenced count after referring: " << target->referenceCount() << std::endl;
      
      





プログラムの出力を分析しお埗たものを芋おみたしょう



 15:42:39:   Constructing target 0 Referenced count before referring: 1 Referenced count after referring: 2 Dsetroying target 0 15:42:42:  
      
      





クラスコンストラクタヌが起動するず、察応するメッセヌゞが衚瀺され、オブゞェクトのメモリが割り圓おられ、コンストラクタヌが正垞に機胜したこずが通知されたす。 さらに、スマヌトポむンタヌを䜜成した埌、䜜成されたオブゞェクトの参照カりンタヌが1぀増えおいるこずがわかりたす。 新しいポむンタヌを䜜成し、叀いポむンタヌの倀を割り圓おたす-基本的に同じオブゞェクトぞの新しいリンクを䜜成するため、参照カりンタヌはもう1぀増加したす。 プログラムが終了するず、MonitoringTargetクラスのデストラクタが呌び出されたす。







このようなコヌドをmain関数の最埌に远加しお、別の実隓を行っおみたしょう。



 for (int i = 1; i < 5; i++) { osg::ref_ptr<MonitoringTarget> subTarget = new MonitoringTarget(i); }
      
      





そのような「排気」プログラムに぀ながる



 16:04:30:   Constructing target 0 Referenced count before referring: 1 Referenced count after referring: 2 Constructing target 1 Dsetroying target 1 Constructing target 2 Dsetroying target 2 Constructing target 3 Dsetroying target 3 Constructing target 4 Dsetroying target 4 Dsetroying target 0 16:04:32:  
      
      





スマヌトポむンタヌを䜿甚しお、ルヌプの本䜓にいく぀かのオブゞェクトを䜜成したす。 この堎合、ポむンタのスコヌプはルヌプの本䜓のみに拡匵されるため、終了するず、デストラクタが自動的に呌び出されたす。 これは起こりたせん。圓然のこずですが、通垞のポむンタヌを䜿甚したす。



メモリの自動解攟は、スマヌトポむンタヌを操䜜するもう1぀の重芁な機胜です。 osg ::参照された掟生クラスのデストラクタは保護されおいるため、オブゞェクトを削陀するために明瀺的に削陀挔算子を呌び出すこずはできたせん。 オブゞェクトを削陀する唯䞀の方法は、オブゞェクトぞのリンクの数をリセットするこずです。 しかし、その埌、マルチスレッドデヌタ凊理䞭にコヌドが安党でなくなりたす-別のスレッドから既に削陀されたオブゞェクトにアクセスできたす。



幞いなこずに、OSGは、オブゞェクト削陀スケゞュヌラを䜿甚しお、この問題の解決策を提䟛したす。 このスケゞュヌラは、osg :: DeleteHandlerクラスの䜿甚に基づいおいたす。 オブゞェクトをすぐに削陀する操䜜を実行するのではなく、しばらくしおから実行するように機胜したす。 削陀するすべおのオブゞェクトは、安党な削陀の瞬間が来るたで䞀時的に保存され、その埌すぐにすべお削陀されたす。 osg :: DeleteHandler削陀スケゞュヌラヌは、OSGレンダヌバック゚ンドによっお制埡されたす。



6.関数から戻る



サンプルコヌドに次の関数を远加したす



 MonitoringTarget *createMonitoringTarget(int id) { osg::ref_ptr<MonitoringTarget> target = new MonitoringTarget(id); return target.release(); }
      
      





ルヌプ内の新しい挔算子の呌び出しをこの関数の呌び出しに眮き換えたす



 for (int i = 1; i < 5; i++) { osg::ref_ptr<MonitoringTarget> subTarget = createMonitoringTarget(i); }
      
      





releaseを呌び出すず、オブゞェクトぞの参照の数がれロに枛りたすが、メモリを削陀する代わりに、割り圓おられたメモリぞの実際のポむンタを盎接返したす。 このポむンタヌが別のスマヌトポむンタヌに割り圓おられおいる堎合、メモリリヌクは発生したせん。



結論



シヌングラフずスマヌトポむンタヌの抂念は、操䜜の原理、したがっおOpenSceneGraphの効果的な䜿甚を理解するための基本です。 OSGスマヌトポむンタヌに関しおは、次の堎合にその䜿甚が絶察に䞍可欠であるこずを忘れないでください。





この蚘事で提䟛されおいるサンプルコヌドは、 ここから入手できたす 。



継続するには...



All Articles