osgEarth的Rex引擎原理分析(二十三)PagerLoader的traverse過程詳解
目標:(十七)中問題48
主要包含兩個過程:
1、以處理過請求的載入
這是真正意義上的載入,剛創建出來的請求是從快取或檔案沒有關聯影像、高程等資料的,需要經過多執行緒處理後才有資料(詳見(十七))。對於這些處理過的請求,在PagerLoader的更新遍歷traverse中會進行實質性的處理。具體如下:
osgEarthDrivers/engine_rex/Loader.cpp void PagerLoader::traverse(osg::NodeVisitor& nv) { for(count=0; count < _mergesPerFrame && !_mergeQueue.empty(); ++count) { Request* req = _mergeQueue.begin()->get(); if ( req && req->_lastTick >= _checkpoint ) { OE_START_TIMER(req_apply); req->apply( getFrameStamp() ); double s = OE_STOP_TIMER(req_apply); req->setState(Request::FINISHED); } _mergeQueue.erase( _mergeQueue.begin() ); } }
(1)限定處理的請求數目
在PagerLoader建立時就會設定這個數目(詳見(十四))
(2)對請求的時間合法性進行判斷
首先是_checkpoint,它是在rex引擎refresh的時候呼叫PagerLoader的clear方法設定的,是一個64位的高精度整型,不同的編譯器定義不同。這個值只設置一次,後面不會再修改。
osgEarthDrivers/engine_rex/Loader.cpp void PagerLoader::clear() { // Set a time checkpoint for invalidating old requests. _checkpoint = osg::Timer::instance()->tick(); }
這裡的tick函式為:
osg/Timer.cpp
Timer_t Timer::tick() const
{
LARGE_INTEGER qpc;
if (QueryPerformanceCounter(&qpc))
{
return qpc.QuadPart;
}
}
這裡的QueryPerformanceCounter為windows的API函式,用於獲取高精度的時間。感覺這裡沒有必要採用這麼高精度的時間吧?
再者是請求的_lastTick,這個值在PagerLoader的load函式中設定,為系統的當前時間。
只有請求的_lastTick在PagerLoader的_checkpoint之後才有意義。
(3)應用請求apply()
(3.1)比較請求的瓦片模型和地圖的版本是否一致
請求的瓦片模型_dataModel在請求的流轉過程中由請求的invoke函式建立,是根據_mapFrame中的版本號來的。地圖的版本號初始值為-1,在新增、刪除、移動圖層後,地圖的版本號都會增加1。
(3.2)將瓦片模型合併到瓦片節點中
(3.2.1)合併顏色(影像)
(3.2.2)合併高程
(3.2.3)合併法線
(3.2.4)合併其它共享層
(3.2.5)更新子瓦片節點
(3.2.6)通知地形節點添加了瓦片
(3.3)設定瓦片節點請求資訊資料標誌TileNode::setDirty
(4)設定請求的狀態為已完成Request::FINISHED
(5)從合併請求佇列_mergeQueue中移除該請求,注意在請求佇列_requests中還存在
2、對一些請求進行裁剪
遍歷所有請求列表_requests中的請求,對每一個請求執行如下操作:
(1)如果請求完成(狀態為FINISHED),設定請求狀態為IDLE,更新暫存器中瓦片的活動記錄,從請求列表中刪除請求。
(2)如果請求還沒有放入請求合併佇列_mergeQueue,並且請求的幀號和當前的幀號差值超過2,更新暫存器中瓦片的活動記錄,從請求列表中刪除請求。
(3)如果請求還已放入請求合併佇列_mergeQueue,並且請求的幀號和當前的幀號差值超過1800,更新暫存器中瓦片的活動記錄,從請求列表中刪除請求。
3、執行父節點的更新遍歷
osgearth中可能用到的幾個全域性例項物件(osgDB::Registry osgEarth::Registry osg::Timer osg::DisplaySetting)
osgEarth::Map::addLayer過程詳解
TileNode::setDirty過程詳解
請求四個狀態的含義(IDLE RUNNING MERGING FINISHED)
請求經過PagerLoader載入時初始化為RUNNING 請求在加入合併佇列_mergeQueue時設為MERGING 請求在執行完apply()時設定為FINISHED 請求在PagerLoader的traverse後會進行裁剪狀態會設為IDLE
什麼時候刪除TileNode節點,不會一直增加吧
暫存器中請求狀態活動記錄的含義Registry::instance()->endActivity( req->getName() );