最長的一幀 作者:王銳(array)
參考的osg源碼版本為 3.6.3
osg自學筆記2——《最長的一幀》
- 0 概況
- 第一日
-
- 具體内容
-
- osgViewer::ViewerBase::frame()函數
- osgViewer::View::init()函數
- 總結
- 第二日
-
- 具體内容
-
- 一種常用的嵌入方式也許是這樣實作的:
- osgViewer::Viewer::getContexts()函數
- 建立預設 GraphicsContext 裝置的方法有以下幾種:
- 總結
0 概況
這裡隻研究一幀的渲染。
while (!viewer.done())
viewer.frame();
第一日
具體内容
osgViewer::ViewerBase::frame()函數
void ViewerBase::frame(double simulationTime)
{
if (_done) return;
// OSG_NOTICE<<std::endl<<"CompositeViewer::frame()"
// <<std::endl<<std::endl;
if (_firstFrame)//判斷第一幀,初始化
{
viewerInit();//初始化
if (!isRealized())
{
realize();
}
_firstFrame = false;
}
advance(simulationTime);
eventTraversal();//事件周遊 滑鼠鍵盤視窗
//周遊更新回調,負責更新 DatabasePager 與 ImagePager 分頁資料處理元件。
updateTraversal();
//周遊渲染,線程處理方法,完成場景的篩選(cull)和繪制(draw)工作。
renderingTraversals();
}
osgViewer::View::init()函數
//完成視景器的初始化工作
void View::init()
{
OSG_INFO<<"View::init()"<<std::endl;
//_eventQueue 用于儲存該視景器的事件隊列。儲存一個 GUIEventAdapter 的連結清單.
//createEvent 函數的作用是配置設定和傳回一個新的 GUIEventAdapter事件的指針。
//osgGA::GUIEventAdapter,用于表達各種類型的滑鼠、鍵盤、觸壓筆和視窗事件。
//initEvent 新事件的類型被指定為 FRAME 事件,即每幀都會觸發的一個事件。
osg::ref_ptr<osgGA::GUIEventAdapter> initEvent =
_eventQueue->createEvent();
initEvent->setEventType(osgGA::GUIEventAdapter::FRAME);
//_cameraManipulator 是視景器中所用的場景漫遊器,
//不同的漫遊器初始化函數是不同的。
if (_cameraManipulator.valid())
{
_cameraManipulator->init(*initEvent, *this);
}
}
上面的代碼将新建立的 FRAME 事件和 Viewer 對象本身傳遞給_cameraManipulator 的init 函數,不同的漫遊器(如 TrackballManipulator、DriveManipulator)會重寫各自的 init 函數,實作自己所需的初始化工作。如果讀者希望自己編寫一個場景的漫遊器,那麼覆寫并使用 osgGA::MatrixManipulator::init 就可以靈活地初始化自定義漫遊器的功能了,它的調用時機就在這裡。
總結
-
解讀成果:
osgGA::EventQueue::createEvent,
osgGA::MatrixManipulator::init,
osgViewer::View::init,
osgViewer::Viewer::viewerInit。
-
懸疑清單:
無
第二日
具體内容
一種常用的嵌入方式也許是這樣實作的:
對于需要将 OSG 嵌合到各式各樣的 GUI 系統(如 MFC,Qt,wxWidgets 等)的朋友來說,osg::GraphicsContext 類是經常要打交道的對象之一。
實作如下:
osg::ref_ptr<osg::GraphicsContext::Traits> traits =
new osg::GraphicsContext::Traits;
osg::ref_ptr<osg::Referenced> windata =
new osgViewer::GraphicsWindowWin32::WindowData(hWnd);
traits->x = 0;
traits->y = 0;
……
traits->inheritedWindowData = windata;
osg::GraphicsContext* gc =
osg::GraphicsContext::createGraphicsContext(traits.get());
Camera* camera = viewer.getCamera();
camera->setGraphicsContext(gc);
……
viewer.setCamera(camera);
這個過程雖然比較繁雜,但是順序還是十厘清楚的:
- 首先設定嵌入視窗的特性(Traits),例如 X、Y 位置,寬度和高度,以及父視窗的句柄(inheritedWindowData);
- 然後根據特性的設定建立一個新的圖形裝置上下文(GraphicsContext),将其賦予場景所用的錄影機。
osgViewer::Viewer::getContexts()函數
//主錄影機沒有建立圖形上下文,是以也就得不到裝置的指針。?這裡添加了裝置上下文啊?
//contextSet這個局部變量是判斷GraphicsContext是否重複。
void Viewer::getContexts(Contexts& contexts, bool onlyValid)
{
typedef std::set<osg::GraphicsContext*> ContextSet;
ContextSet contextSet;
contexts.clear();
//首先判斷場景的主錄影機_camera 是否包含了一個有效的GraphicsContext 裝置
if (_camera.valid() &&
_camera->getGraphicsContext() &&
(_camera->getGraphicsContext()->valid() || !onlyValid))
{
contextSet.insert(_camera->getGraphicsContext());
contexts.push_back(_camera->getGraphicsContext());
}
//然後再周遊所有的從錄影機_slaves,
//将所有找到的 GraphicsContext 圖形上下文裝置記錄下來。
//随後,将這些 GraphicsContext 的指針追加到傳入參數(contexts 向量組)中,
//并使用std::sort 執行了一步排序的工作,所
for(unsigned int i=0; i<getNumSlaves(); ++i)
{
Slave& slave = getSlave(i);
osg::GraphicsContext* sgc = slave._camera.valid() ?
slave._camera->getGraphicsContext() : 0;
if (sgc && (sgc->valid() || !onlyValid))
{
if (contextSet.count(sgc)==0)//不重複記錄
{
contextSet.insert(sgc);
contexts.push_back(sgc);
}
}
}
}
建立預設 GraphicsContext 裝置的方法有以下幾種:
1、讀取 OSG_CONFIG_FILE 環境變量的内容:如果使用者在這個環境變量中定義了一個檔案路徑的話,那麼系統會嘗試用 osgDB::readObjectFile 函數讀入這個檔案,使用 cfg 插件進行解析;如果成功的話,則調用 osgViewer::Viewer::take 函數,使用配置資訊設定目前的視景器。這些工作在 osgViewer::Viewer::readConfiguration 函數中實作。
2、讀取 OSG_WINDOW 環境變量的内容:如果使用者以“x y w h”的格式在其中定義了視窗的左上角坐标(x,y)和尺寸(w,h)的話(注意要以空格為分隔符),系統會嘗試使用 osgViewer::View::setUpViewInWindow 函數來建立裝置。
3、讀取 OSG_SCREEN 環境變量的内容:如果使用者在其中定義了所用螢幕的數量的話,系統會嘗試用 osgViewer::View::setUpViewOnSingleScreen 函數,為每一個顯示屏建立一個全螢幕的圖形視窗;如果同時還設定了 OSG_WINDOW,那麼這兩個環境變量都可以起到作用,此時将調用 setUpViewInWindow 函數。
4、如果上述環境變量都沒有設定的話(事實上這也是最常見的情況),那麼系統将調用osgViewer::View::setUpViewAcrossAllScreens 函數,嘗試建立一個全屏顯示的圖形裝置。
那麼,下文就從這幾種圖形裝置建立的方法開始。至于後面的路,果然遙遙無期呢。
總結
-
解讀成果:
osgViewer::Viewer::getContexts,
osgViewer::Viewer::readConfiguration。
-
懸疑清單:
類變量_cameraWithFocus 的意義是什麼?
————完結————