探索未知種族之osg類生物---器官初始化四

探索未知種族之osg類生物---器官初始化四
上一節我們對完成了對osg生物內部非常重要器官graphicsContext的初始化工作。這樣就可保證我們場景中至少有一個graphicContext存在,不至於剛出生就面臨夭折。我們根據上一節中osg代碼的研究也就知道了,在我們正常使用osg時,是怎麼完成對camera以及graphicContext的創建的了。

探索未知種族之osg類生物---器官初始化四

回到Viewer::realize()中我們繼續向下看,現在我們對osg::DisplaySettings以及osg::GraphicsContext::WindowingSystemInterface,有了新的認識,我在這裏再補充一張camera,graphicContext以及windowingSystemInterface的關係圖有利於大家進一步瞭解osg的內部組成。

探索未知種族之osg類生物---器官初始化四

回到Viewer::realize()中我們繼續向下看,得到所有的GraphicsContext,遍歷所有的GraphicsContext,然後判斷是否設置了同步交換緩衝區(這一般是渲染的最後一步),這是osg提供的多機同步swapbuffer機制,他會默認調用內置的swapbuffer的回調函數(osg::SyncSwapBuffersCallback中,作用主要是等待client端的同步鎖,實現多機同步執行swapbuffer)。如果developer想幹預的話 可以調用 osg::GraphicsContext::setSwapCallback(SwapCallback* rc)來設置自定義的緩存交換回調。自定義的回調必須調用GraphicsContext::swapBuffersImplementation()函數.

再根據所依據的平臺(windows,linux,mac等)默認制定的,或者用戶後期修改的最大紋理池和最大對象緩衝池的大小,進一步對各個graphicsContext的相應屬性值進行設置。然後正式完成對graphicsContext的初始化定義,下一步就是通過調用gc.realize()來使graphicsContext處於可用的狀態。Osg::GraphicsContext::realize()函數的實現都是在它的繼承類中通過realizeImplementation()函數完成的。
探索未知種族之osg類生物---器官初始化四

特別是windows平臺的實現,使用windows+opengl的同學對這一段GraphicsWindowWin32::realizeImplementation()函數肯定非常瞭解,因爲這裏會涉及到很多windows平臺特有的一些屬性,就不做過多的介紹了,以後有機會我會再寫一份opengl的入門教程,其中肯定會提到函數中涉及的東西。敬請期待。

當GraphicsContext可用了,就需要更新上下文gc->makeCurrent()。那我們就看看GraphicsContext::makeCurrent()完成了什麼工作。

gc->makeCurrent()
GraphicsContext::makeCurrent()首先判斷opengl與osg是否是同一個線程,(使用qt5+osg3.x的同學一定遇到過osg的threadmode只能設置singlethread。其他三種threadmode都會報一個同樣的錯誤,錯誤的原因就是這裏。至於怎麼完美的結合qt5與osg3,請移步到我的github下 https://github.com/JimmieKJ/osgQTWidget 有具體的實現細節)。其實GraphicsContext::makeCurrent()的根本是通過調用子類的makeCurrentImplementation()實現。

探索未知種族之osg類生物---器官初始化四

當我們移步到bool GraphicsWindowWin32::makeCurrentImplementation()同樣會發現,這裏和使用opengl的程序有很大的相同之處,其實就是把dc和rc進行綁定。當makeCurrentImplementation返回true的時候,就代表graphicsContext更新成功。然後就是opengl的思路,需要解綁hc和rc防止資源浪費,這就需要調用gc->releaseContext(),其實就是調用子類的releaseContextImplementation()函數。

再次聚焦到realize函數上(/src/osgViewer/Viewer.cpp::realize()函數),_incrementalCompileOperation,用於預編譯GraphicContext,主要作用是,想在程序運行開始時就加在一個資源文件但是又不想或者沒有到顯示到界面的時機,則會用到這個預加載操作。具體的用法如下:

//從Viewer獲取 osgUtil::IncrementalCompileOperation的指針:

osgUtil::IncrementalCompileOperation* pIcompOperation = viewer.getIncrementalCompileOperation();//從Viewer獲取 osgUtil::IncrementalCompileOperation的指針:

// 創建compileSet:

osg::ref_ptr compileSet = osgUtil::IncrementalCompileOperation::CompileSet(NODE,true);

//從CompileCompletedCallback派生新類,然後重寫Completed函數,在內部隱藏節點:

//將 派生類 綁定到 compileSet。

compileSet->compileSet->_compileCompletedCallback = newCompileCompletedCallback;

//設置 IncrementalCompileOperation 過期策略

pIcompOperation->setCompileAllTillFrameNumber(50);

再往下就是使鼠標聚焦到osg的繪製窗口上這個一個功能。

// initialize the global timer to be relative to the current time.

osg::Timer::instance()->setStartTick();

// pass on the start tick to all the associated event queues

setStartTick(osg::Timer::instance()->getStartTick());

// configure threading.

setUpThreading();
首先調用 osg::Timer::setStartTick 函數,啓動 OSG 內部定時器並開始計時。

隨後, Viewer::setStartTick 函數的工作是找到當前視景器和所有 GraphicsContext 設備的事件隊列_eventQueue,並設定它們的啓動時刻爲當前時間。下一行是調用 ViewerBase::setUpThreading 函數(這個多線程問題我們以後再深入討論)

請回到 realize 函數,現在這個函數的執行已經接近了尾聲,不過我們又遇到了一個問題:編譯上下文(也就是 Compile Contexts,)如果要啓用它的話並不困難,只需要在調用 realize 之前執行:osg::DisplaySettings::instance()->setCompileContextsHint(true);隨後,正如您在 realize 函數的 最後一個for循環看到的,系統將設法遍歷所有可能的GraphicsContext 設備,針對它們分別再各自添加一個新的 GraphicsContext 設備(也就是說如果系統中已經有了數個圖形上下文,那麼現在又將新增同樣數量的圖形上下文與之對應),所用的函數爲 GraphicsContext::getOrCreateCompileContext。

這之後,分別執行了創建圖形線程,設置 CPU 依賴性,以及啓動圖形線程的工作,具體的實現內容可以暫時忽略。觀察 getOrCreateCompileContext 函數的內容,很快我們就可以發現其中的重點:這些新增的 GraphicsContext 對象使用了 pBuffer 的特性,並與對應的已有對象共享同一個圖形上下文(Traits::sharedContext 特性)。事實上,這是 OSG 利用 OpenGL 的像素緩存(Pixel Buffer)技術,爲圖形上下文的後臺編譯提供的一種新的解決方案。這樣不僅可以提高圖形刷新的速度,還可以方便用戶爲某一特定的 GraphicsContext 設備添加特殊的處理動作,方法是使用osg::GraphicsContext::getCompileContext 獲取後臺圖形上下文,再使用 GraphicsContext::add函數向其中追加 osg::Operation 對象,類似的例子可以參看 osgterrain。
歡迎大家來我的新家看一看 www.3wwang.cn

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章