1. 程式人生 > >osgEarth的Rex引擎原理分析(二十三)PagerLoader的traverse過程詳解

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() );