osgDB庫允許使用者程式加載、使用和寫入3D資料庫,它采用插件管理的架構,可以支援大量常見的2D圖形和3D圖形檔案格式。osgDB負責維護插件的資訊系統資料庫,并負責檢查将要被載入的OSG插件接口的合法性。由于大型3D地形資料通常是多段資料塊的組合體,是以,應用程式從檔案中讀取各部分資料庫資訊時,需要在不幹擾目前渲染的前提下以背景線程的方式進行,osgDB::DatabaseParger提供了這樣的功能。
插件的不足之處在于,其設計過程中隻能遵循固定的格式和工作模式進行程式設計,它的一切行為都無法超出主系統所提供的公共接口規範。
osg插件是一組動态連結庫,其中實作了osgDB頭檔案ReaderWriter定義的接口。OSG不可能查找并加載所有的插件以擷取它們支援的檔案格式,這樣,在程式啟動時将會是一個很大的開銷,是以,OSG使用職責鍊(Chain of Responsibility)的設計模式,以加載盡量少的插件。當使用者程式嘗試使用osgDB讀取或寫入檔案時,OSG将按照如下步驟來查找合适的插件:
1. OSG搜尋已注冊的插件清單,查找支援檔案格式的插件。開始時已注冊插件清單僅包含了Registry類構造函數中注冊的插件。如果OSG找到了可以支援此檔案格式的插件,并成功執行了I/O操作,那麼它将傳回相應的資料。
2. 如果沒有發現可以支援此格式的已注冊插件,或者I/0操作失敗,那麼OSG将根據前面所述的檔案命名規則建立插件檔案的名稱,并嘗試讀取相應的插件庫。如果讀取成功,OSG将添加此插件到已注冊插件清單中。
3. OSG将重複步驟1,如果檔案I/O的操作再次失敗,OSG将傳回失敗資訊。
就earth格式模型做一個簡要說明,在加載earth檔案時,會根據格式在電腦的所有環境變量中找到對應的dll檔案(osgdb_earth.dll),并試着讀取osgdb_earth.dll,加載并成功執行osgdb_earth.dll的宏定義,就會成功解析檔案。
代碼中具體查找讀取插件流程如圖所示:
函數執行順序為:
osg::Node *node=osgDB::readNodeFile(某種類型的檔案路徑),這個語句是osg讀取節點資料常用的函數,下面對這個函數進行跟蹤,簡單介紹下資料的處理過程,友善自己對osgDB的插件進行簡單的修改。
1. osg::Node *readNodeFile(const std::string &filename)
2. ①的具體實作,該函數的作用是調用osgDB/Registry的單例,進行資料的解析,參數options預設為空。
3. ②的具體實作,由于options參數為空,并且_readFileCallback為空,是以函數直接執行③
ReaderWriter::ReadResult readNode(const std::string& fileName,const Options* options, bool buildKdTreeIfRequired=true)
{
ReaderWriter::ReadResult result;
if (options && options->getReadFileCallback()) result = options->getReadFileCallback()->readNode(fileName,options);
else if (_readFileCallback.valid()) result = _readFileCallback->readNode(fileName,options);
else result = readNodeImplementation(fileName,options); ③
if (buildKdTreeIfRequired) _buildKdTreeIfRequired(result, options);
return result;
}
4. ③的具體實作,直接執行函數④
5. ④的具體實作,由于readFunctor的options為空,是以函數在中間沒有做實際的資料處理,直接執行⑤
6. ⑤的具體實作,主要的思想是:
先從_rwList查找是否可以解析目前類型的資料,如果能解析,直接傳回解析結果;
如果不能解析,根據目前檔案名,建立一個跟目前名稱相關的動态庫的名稱,然後使用loadLibrary加載該動态庫,加載成功後,_rwList這裡面存儲的對象的數目會增加。
工程中沒有發現有對_rwList做增加操作的代碼,那麼_rwList是怎麼增加的?關鍵點是,對于每一個插件dll的注冊,都需要定義全局變量,方法為REGISTER_OSGPLUGIN(VR, ReaderWriterVR),這個宏調用生成了一個靜态的對象osgDB::RegistryReaderWriterProxy,這個對象的作用就是增加_rwList的對象數目,這是注冊機制的關鍵。
這裡說一下"#" "##"的含義:"#"将後面跟的變量由引号包含,如#value會解析成"value"。 "##"将前後兩個值連接配接,去掉空格,如A##B會解析成AB。
7. ⑥doRead函數就是利用osgDB機制,第三方插件庫osgDB_earth中的讀取方式,正式開始讀取本地earth檔案,(為什麼是本地,因為讀取伺服器似乎是另外一種處理方案)!
8. 繼續實作進入ReaderWriterOsgEarth的readNode函數中,看到序列化函數,關于序列化,請看另一篇部落格。
轉載連結:[osg]osgDB的加載機制,使用3DS插件做參考(轉,整理現有osgDB資料) - 南水之源