[OSG][轉]osg格式文件


轉自:http://blog.csdn.net/timothyfly/article/details/7826139

osg格式文件中如何處理多個節點共享一個子節點

 

下面一段程序中,共有三個Group類型根節點:root,grp1和grp2;兩個Geode類型節點:geode1和geode2。他們之間的從屬關系是:grp1,grp2和geode2是root的孩子,geode1和geode2是grp1的孩子,geode2是grp2的孩子。

.osg格式的文件存儲像geode2這個的節點時,采用'Use'這個關鍵詞。

---------------------------------------------------------------------------------------------

.osg文件內容:

Group {
  name "root"
  nodeMask 0xffffffff
  cullingActive TRUE
  num_children 3
  Group {
    UniqueID Group_0
    name "grp1"
    nodeMask 0xffffffff
    cullingActive TRUE
    num_children 2
    Geode {
      UniqueID Geode_1
      name "geode1"
      nodeMask 0xffffffff
      cullingActive TRUE
      num_drawables 1
      Geometry {
        useDisplayList TRUE
        useVertexBufferObjects FALSE
        PrimitiveSets 1
        {
          DrawArrays LINE_STRIP 0 3
        }
        VertexArray Vec3Array 3
        {
          0 1 0
          0 0 0
          1 1 0
        }
      }
    }
    Geode {
      UniqueID Geode_2
      name "geode2"
      nodeMask 0xffffffff
      cullingActive TRUE
      num_drawables 1
      Geometry {
        useDisplayList TRUE
        useVertexBufferObjects FALSE
        PrimitiveSets 1
        {
          DrawArrays LINE_STRIP 0 3
        }
        VertexArray Vec3Array 3
        {
          1 0 0
          2 1 0
          2 0 0
        }
      }
    }
  }
  Group {
    UniqueID Group_3
    name "grp2"
    nodeMask 0xffffffff
    cullingActive TRUE
    num_children 1
    Use Geode_2
  }
  Use Geode_2
}
-----------------------------------------------------------------------------------------

osg程序代碼:

#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osg/Point>
#include <osg/LineWidth>
#include <osgDB/WriteFile>

// 根據一組點集生成一個Geode對象
osg::ref_ptr< osg::Geode > createProfileGeode( int size, osg::Vec3 *points )
{
 osg::ref_ptr< osg::Geode > geode = new osg::Geode();
 osg::ref_ptr< osg::Geometry > pointsGeom = new osg::Geometry();
 osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array( size, points);
 pointsGeom->setVertexArray(vertices);

 pointsGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP,0,vertices->size()));
 geode->addDrawable(pointsGeom);

 return geode.release();
}
int main( int argc, char** argv )
{
 osg::Vec3 myCoords1[]=
 {
  osg::Vec3(0,1,0),
  osg::Vec3(0,0,0),
  osg::Vec3(1,1,0)
 };
 osg::Vec3 myCoords2[]=
 {
  osg::Vec3(1,0,0),
  osg::Vec3(2,1,0),
  osg::Vec3(2,0,0)
 };


 osg::ref_ptr< osg::Geode > geode1 = createProfileGeode( sizeof(myCoords1)/sizeof(myCoords1[0]), myCoords1 );
 osg::ref_ptr< osg::Geode > geode2 = createProfileGeode( sizeof(myCoords2)/sizeof(myCoords2[0]), myCoords2 );
 geode1->setName("geode1");
 geode2->setName("geode2");

 osg::ref_ptr<osg::Group> root = new osg::Group;
 osg::ref_ptr<osg::Group> grp1 = new osg::Group;
 osg::ref_ptr<osg::Group> grp2 = new osg::Group;
 root->setName("root");
 grp1->setName("grp1");
 grp2->setName("grp2");

 grp1->addChild(geode1);
 grp1->addChild(geode2);//geode2的第一個父節點
 grp2->addChild(geode2);//geode2的第二個父節點

 root->addChild( grp1 );
 root->addChild( grp2 );
 root->addChild(geode2);//geode2的第三個父節點

 osgDB::writeNodeFile( *root, "test.osg" );

 osgViewer::Viewer viewer;
 viewer.setSceneData( root.get() );
 return viewer.run();
}

 

 

參考:http://blog.csdn.net/gelu1231/article/details/6655679

OSG第二代文件序列化存儲分析

 

我們以將節點寫入文件為例,節點讀取與此相同,看看究竟是如何將節點寫入文件的,我們從文件讀寫插件的最頂層入口函數來看,即
virtual WriteResult writeNode( const osg::Node& node, const std::string& fileName, const Options* options ) const
因為osg第二代文件格式讀寫插件同時支持文本、二進制以及XML格式的文件,所以,在寫文件前要確定具體要寫入什么文件,讀寫不同的文件格式需要用到的序列化器不同,文件打開方式也不同,
進入writeNode后會調用Options* prepareWriting( WriteResult& result, const std::string& fileName, std::ios::penmode& mode, const Options* options ) const
該函數就完成上面的工作,該函數根據文件擴展名判斷如果是osgt格式,就向options中添加文本格式的參數選項,如果是osgx格式,就添加XML格式選項,以讓后續的寫入操作根據該選項進行相應文件格式的讀寫,否則以二進制格式讀寫;
做好以上准備工作后,就像以前一樣將文件數據讀入文件流開始向文件流寫入數據,即進入virtual WriteResult writeNode( const osg::Node& node, std::stream& fout, const Options* options ) const
針對文本、XML、二進制格式的文件分別對應三種不同的輸出指示器,在OutputStream類中進行數據寫入時要調用相應的輸出指示器,所以,首先要獲取相應類型的輸出指示器;該工作通過函數OutputIterator* writeOutputIterator( std::stream& fout, const Options* options )來完成,該函數從options中查找是否有文本或者XML的文件格式選項(從剛才的分析我們已經知道,如果是osgt或osgx格式的話,在prepareWriting中已經添加進來),如果有對應的選項,就創建相應的輸出指示器,如果兩種都沒有,就創建二進制格式的輸出指示器,除文本格式之外,對於XML格式和二進制格式,該函數除了創建相應的輸出指示器外,同時還像文件流寫入了文件頭信息,對於XML格式,直接寫入XML文件頭,對於二進制格式,寫入MD5碼;從上面的分析我們不難看出,對於文本和XML格式的文件,我們簡單的添加supportsExtension來讓插件支持我們自己的擴展名文件類型是做不到的,插件會把它當做二進制來對待,無法正確處理,所以,擴展名得擴展只適用於二進制格式;
得到輸出指示器后構造一個OutputStream對象開始寫數據。
首先是調用void OutputStream::start( OutputIterator* outIterator, OutputStream::WriteType type ),將輸出指示器傳給OutputStream並向文件流寫入文件的標志信息,如文件內容類型標示(如場景、對象、圖像)、版本號等信息,接下來調用void OutputStream::writeObject( const osg::Object* obj )從節點對象讀取節點數據。下面進入該函數,首先獲取一個對象唯一ID,然后向流中寫入對象類名(如osg::Group),然后寫入開始大括號’{’,接下來寫入對象的數據,寫入對象數據后寫入結束大括號’}’;上面的寫入操作都是通過剛才傳入的輸出指示器來完成;
        下面我們將如何寫入對象數據來分解開進行分析,這是寫入操作的核心所在。該過程在void OutputStream::writeObjectFields( const osg::Object* obj )中完成,我們現在就來看看writeObjectFields都玩了哪些花樣;一定要看仔細,正是它玩的花樣,才使得我們可以在不修改該文件操作插件的情況下通過擴展的方式讓自己的節點對象也可以讀寫的,所以一定要看仔細了;
首先要根據類名獲取該類的wrapper(所有要能夠將數據寫入文件的類都要對應有一個該類的包裝類wrapper,所有的wrapper統一由wrapper管理器來管理,每添加一個wrapper類型,自己要將自己注冊到該管理器,否則無法對該類型的對象進行讀寫操作),如果要讓自己的對象能夠進行文件讀寫,需要擴展自己的類的wrapper類,在wrapper類中定義要讀寫哪些數據字段;
類是有繼承關系的,那么在進行讀寫操作時,還是需要各個類自己操作自己本身的成員,一個子類只負責自己擴展出來的成員字段的讀寫操作,父類的那些成員又父類的wrapper去處理,各司其職。而系統本身是沒有辦法知道一個子類上面都有哪些父類、祖父類等關聯類信息的,所以需要我們告訴它,該工作通過在構造wrapper時指定,將該子類關聯的所有上層類名稱傳進去,即associates參數,在每個wrapper類中有一個associates的數組。
繼續上面的分析過程,在writeObjectFields中獲取到要寫入文件的節點對象(根據類名獲得,所以,自己派生的對象要能像osg對象那樣能夠用這種方式進行讀寫操作,必須從osg::Object派生,且必須實現ClassName接口)對應的wrapper后,遍歷該wrapper的關聯類數組,然后再根據關聯類獲取對應的wrapper進行數據寫入工作。在繼續該寫入過程詳細分析之前,需要補充說明一下,注冊wrapper時向該wrapper傳入的管理類信息包含了該類本身,所以,這里的寫入操作統一在遍歷關聯類數組過程中進行,所以,在注冊wrapper時,一定要在最后將類自身也添加到關聯類信息里,否則只能讀寫上層類的數據,本類本身的信息會丟失。
接下來的分析就相對要集中了,就是針對具體的類類型進行數據的寫入操作了。如果需要向文件中寫入每個類的字段剛要信息,就將每個類的屬性字段名稱及類型以剛要的形式寫入,然后再寫該類的數據信息,默認情況下不寫入;那么我們接着看寫對象的數據字段的內容。該過程由bool ObjectWrapper::write( OutputStream& os, const osg::Object& obj )完成,下面我們來進到里面探個究竟。
在分析之前我們需要插入一段前奏,然后才能繼續下面的過程。通過上面的分析,我們知道怎么讓插件能夠讀寫每種類對象了(通過擴展wrapper並注冊),也知道了怎么區別對待不同類型的文件(Txt、XML、Binary,通過不同的指示器),還有一個重要的問題沒有提到,那就是如何知道要讀寫一個類的哪些數據成員,以及如何調用數據獲取接口。在注冊wrapper時,除了給wrapper設置其對應的類名、類對象原型、關聯類描述之外,還要設置通過何種序列化器對哪些字段進行讀寫操作。我們通過代碼不難看到ADD_USER_SERIALIZER、ADD_OBJECT_SERIALIZER、ADD_DOUBLE_SERIALIZER等等身影,通過這些宏就設定好了要讀寫該wrapper對應的類的數據字段。一個對象有多少屬性字段,就會對應多少序列化器,每個序列化器負責該屬性字段的具體的讀寫操作,wrapper對象會將所有加入的序列化器保存在一個數組中。此外,對於不同的字段數據類型,對應有相應類型的序列化器,如int、double、osg::Vec3d以及對象類型等等,操作相應類型的屬性字段要選擇正確的序列化器。
通過上面的分析,我們應該知道了如何設定類的哪些屬性數據可進行文件存儲,接下來我們來看看是如何調用相關的屬性訪問接口來進行數據存取的。方法用的就是函數指針,在添加序列化器時,相應的序列化器會根據傳入的屬性字段名稱自動創建對應的屬性訪問函數指針(getter、setter)或字段讀寫函數指針(reader、writer)並將其傳遞給序列化器的構造函數(函數指針作為函數參數傳遞,這些函數都不會有重載函數,基本都是getXXX、setXXX,大可放心使用),然后序列化器會記錄下來這些函數指針,在序列化器進行數據字段的讀寫時調用該函數指針來進行數據字段的讀寫操作;
好了,前奏到此為止,不要忘了我們還沒有進入bool ObjectWrapper::write( OutputStream& os, const osg::Object& obj )呢。現在我們來看這個函數就很簡單了,它也就是遍歷該wrapper對象的所有序列化器,調用序列化器的write函數將每個屬性字段寫進去。對於UserSerializer是傳遞屬性字段讀寫函數指針,對於其他類型的序列化器,傳遞的是屬性字段的訪問函數指針,兩者最終都是通過OutputStream的”<<”重載操作符將字段值寫入到流中,進一步我們可以看到OutputStream的”<<”重載操作符函數最終通過調用最開始時傳入OutputStream的輸出指示器的類型寫入函數來完成最終的寫入操作;針對不同類型的格式控制(txt、XML、Binary)都是在相應的輸出指示器中完成。
現在我們知道,通過該插件,我們要讓該插件支持我們自己擴展的對象類型,只要創建相應的wrapper並注冊進來就OK,非常方便。另外一方面,可能在開發自己的應用系統時,需要定義自己的文件格式,這時,如果是二進制的格式的話,直接通過supportsExtension添加自己的擴展名支持即可,在應用系統中通過addFileExtensionAlias來指定一下。此外還有一個重要的擴展可能對我們開發自己的系統更為重要,那就是文件數據的加密存儲,簡單起見我們可以重寫插件的writeOutputIterator和readOutputIterator,在文件頭中加入自己的加密數據,如base64/md5加密數據,並做相應的檢測處理,通過派生新的compressor我們就可以實現對文件內容的壓縮和解壓縮,或者加密和解密,或者加入自己的頭信息等等,都非常方便;

 

 

 

轉一個別人細讀cow.osg的

 

對,就是那只著名的奶牛。

//Group節點,可有子節點。
Group {

UniqueID Group_0         //Gourp名稱
DataVariance STATIC   //不知道用來干嘛,一般都是static
cullingActive TRUE      //參與culling?
num_children 1               //子節點數

Geode {   //子節點是Geode節點(Geode節點是葉節點,它不會再有子節點,可以與任意多個Drawable的對象關聯)

    DataVariance DYNAMIC
    name "cow.osg"              //Geode名稱,應該是模型路徑吧
    cullingActive TRUE       //參與culling
    num_drawables 1           //可繪制元素Drawable對象的數目,1

    Geometry {   //Drawable :Gemetry,是可繪制對象類型之一。用指定頂點數據,繪制幾何體。

      DataVariance DYNAMIC

      StateSet {   //渲染狀態。分為渲染屬性和渲染模式兩部分。是個狀態值,直到子節點重新設置前,它的值一直沿節點樹向下有效。
        DataVariance STATIC
        rendering_hint OPAQUE_BIN    //和渲染有關的
        renderBinMode INHERIT            //和渲染有關的
        GL_CULL_FACE OFF                 //和裁剪有關的
        GL_LIGHTING ON                       //和裁剪有關的

        Material {   //材質
          DataVariance STATIC
          ColorMode OFF                    //光的啥啥
          ambientColor 0.5 0.5 0.5 1     //環境光
          diffuseColor 1 1 1 1               //漫反射
          specularColor 1 1 1 1             //鏡面反射
          emissionColor 0 0 0 1            //自發光
          shininess 1                              //????????
         } ////材質結束

        textureUnit 0 { //紋理單元,1,可以多個。序數依次。

          GL_TEXTURE_GEN_S ON   //啥啥啥???
          GL_TEXTURE_GEN_T ON   //啥啥啥???
          GL_TEXTURE_2D ON           //啥啥啥???

          Texture2D {    //2D的貼圖
            DataVariance STATIC
            file "Images/reflect.rgb" //貼圖文件
            wrap_s REPEAT             //repeat嘛,很容易懂
            wrap_t REPEAT
            wrap_r REPEAT
            min_filter NEAREST_MIPMAP_LINEAR //什么filter
            mag_filter LINEAR                                        //另一個filter
            internalFormatMode USE_IMAGE_DATA_FORMAT //??
            subloadMode OFF                                                               //??
          }////Texture結束

          TexGen {   //貼圖坐標?
            DataVariance STATIC
            mode SPHERE_MAP   //啥啥球面?——"環境反射貼圖,選球面就可以了"?
          }////貼圖坐標結束

        }////紋理單元1結束

      }////Geometry的stateset結束

      useDisplayList TRUE    //顯示模型的列表????

      Primitives 1   //貌似是Gemotry的圖元信息
      {
        DrawArrayLengths TRIANGLE_STRIP 0 984    //畫幾何面?985個?
        {
          3
          // 略一堆面?的數值。。。3是指3邊形么?@v@
        }
      } ////primitives完

      VertexArray 7772   //頂點坐標
      {
        // 略一堆表示頂點的數值。
        0.701499 2.00244e-05 0.71267
        0.501693 4.00296e-05 0.865046
        0.465203 0.372921 0.802818
      }

      NormalBinding PER_VERTEX     //法向量綁定方式,每個頂點
      NormalArray 7772                          //法向量數組
      {
        0.254622 -0.918791 -0.301648
        0.440603 -0.85537 -0.272417
        0.244499 -0.920072 -0.306084
      }

      ColorBinding OVERALL      //Geometry的顏色綁定,啥意思我也不知。

      ColorArray Vec4Array 1     //顏色的值
      {
        0.8 0.8 0.8 1
      }

      TexCoordArray 0 Vec2Array 7772 //應該是修飾頂點的啥東西=.=
      {
        0 0
        // 略一堆。。。。。。數值。
      }

    }////Geometry完

}////Geode完

}////Group完

 

 

 

 

 

1   總結一下  

一個根節點Group,名字叫Group0,它的屬性和參數包括:
UniqueID
DataVariance
cullingActive
num_children
1個Geode

Geode,名字叫"cow.osg",它的屬性參數包括

     DataVariance
    name "cow.osg"
    cullingActive
    num_drawables
    1個Geometry

這1個Geometry的屬性參數包括

      DataVariance
      StateSet
      useDisplayList
      Primitives
      VertexArray
      NormalBinding 
      NormalArray 
      ColorBinding
      ColorArray
      TexCoordArray

其中StateSet又有

        DataVariance STATIC
        rendering_hint
        renderBinMode
        GL_CULL_FACE
        GL_LIGHTING
        Material
         1個textureUnit

Material和textureUnit又有各自的blablabla.....


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM