当前位置:osgViewer/Viewer.cpp 第514行 osgViewer::Viewer::realize()
setUpViewOnSingleScreen();setUpViewAcrossAllScreens()和之前的setUpViewInWindow是一样的流程。基本一致。都是通过apply()方法来执行了相应config的类型所对应的configure()方法。
这里注意一下setUpViewAcrossAllScreens对应的configure()方法。
当前位置:osgViewer/AcrossAllScreens.cpp 第24行 AcrossAllScreens::configure(osgViewer::View& view)
类似之前的setUpViewInWindow,获取WindowingSystemInterface的指针wsi。如果wsi为空,则无法创建窗口。尝试获取osg::DisplaySettings的指针。也就是获取一些viewer所需的display settings.
接着就设置了主相机的透视投影矩阵的内容。
这里通过了WindowingSystemInterface来获取了屏幕的数量
unsigned int numScreens = wsi->getNumScreens(si);
如果我们需要在自己的程序中获取屏幕分辨率,或者设置屏幕刷新率的话,也可以使用同样的方法,调用 getScreenResolution, setScreenResolution 和 setScreenRefreshRate等相关函数即可。具体的实现方法可以参见 GraphicsWindowWin32.cpp 的源代码。后面的内容就和之前的SingleView里的configure函数一致了。
新建显示设备特性实例等等一系列的操作。这里有一点增加的内容。
view.assignSceneDataToCameras();字面上理解就是将场景数据分配给了视景器的相机。让我们去看看这个方法具体做了什么吧。
当前位置:osgViewer/View.cpp 第778行 osgViewer::View::assignSceneDataToCameras()
这其中包括以下几项工作:
1、对于场景漫游器_cameraManipulator,执行其 setNode 函数和 home 函数,也就是设置漫游器对应于场景图形根节点, 并回到其原点位置。不过在我们使用 setCameraManipulator函数时也会自动执行同样的操作。
2、将场景图形赋予主摄像机_camera,同时设置它对应的渲染器(Renderer)的相关函数。这里的渲染器起到了什么作用?还是先放到悬疑列表中吧,不过依照我们的解读速度,这个问题可能会悬疑很久。
3、同样将场景图形赋予所有的从摄像机_slaves,并设置每个从摄像机的渲染器。
以上是复制《最长的一帧》原文,这里大概看了一下这个函数。反正也看不懂。但知道了一点就是,场景漫游器是被设置来对应于场景图形根节点的。
再次回到realize()函数吧。
当前位置:osgViewer/Viewer.cpp 第525行 osgViewer::Viewer::realize()
判断缺省的GraphicsContext是否成功,判断是否建好了窗口,如果这个时候还是没有窗口,那就别继续玩了。你走吧,妈妈不让我和傻子玩。
接着根据代码注释,
// get the display settings that will be active for this viewer获取视景器需要的显示设置
// pass on the display settings to the WindowSystemInterface.将这些显示设置传给WSI
(摔,这个realize()函数读到这里真的是爆炸了,根本看不懂。挖的太深了,坚持坚持!!看不懂就背吧!!)
接着获取了maxTexturePoolSize,maxBufferPoolSize,没有注释,大神也没写,字面上感觉就是最大能保存的Texture和Buffer的数量吧。
然后就开始遍历GraphicsContext设备(通常只有一个)
for(Contexts::iterator citr = contexts.begin(); citr != contexts.end();
对于每个 GraphicsContext 指针 gc
osg::GraphicsContext* gc = *citr;,依次执行:
if (ds->getSyncSwapBuffers()) gc->setSwapCallback(new osg::SyncSwapBuffersCallback);
// set the pool sizes, 0 the default will result in no GL object pools.
gc->getState()->setMaxTexturePoolSize(maxTexturePoolSize);
gc->getState()->setMaxBufferObjectPoolSize(maxBufferObjectPoolSize);
gc->realize();
if (_realizeOperation.valid() && gc->valid())
{
gc->makeCurrent();
(*_realizeOperation)(gc);
gc->releaseContext();
}
首先就是设置pool sizes,然后又对gc进行realize()操作。这里进去看看GraphicsContext的realize()方法吧。
当前位置:osg/GraphicsContext.cpp 第509行 GraphicsContext::realize()
非常短的代码,返回bool类型,判断了realizeImplementation(),其实实质就是这个函数。查看这个函数的定义,发现有三处,有两处都是纯虚函数。
virtual bool osgViewer::GraphicsWindow::realizeImplementation()
virtual bool osgViewer::GraphicsWindowEmbedded::realizeImplementation()
bool osgViewer::GraphicsWindowWin32::realizeImplementation()
之前尝试创建缺省的图形上下文设备时,我们使用下面一句代码来创建的。
osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits.get());
现在来看看这个createGraphicsContext()的内容。
当前位置:osg/GraphicsContext.cpp 第509行 GraphicsContext* GraphicsContext::createGraphicsContext(Traits* traits)
ref_ptr &wsref = windowingSystemInterfaceRef();
if ( wsref.valid())
{
// catch any undefined values.
if (traits) traits->setUndefinedScreenDetailsToDefaultScreen();
return wsref->createGraphicsContext(traits);
}
1、视景器 Viewer 的主/从摄像机均需要使用 setGraphicsContext 设置对应的图形设备上下文,实际上也就是对应的显示窗口;
2、 GraphicsContext 的创建由平台相关的抽象接口类 WindowingSystemInterface 负责,对于 Win32 平台而言, 这个类是由 GraphicsWindowWin32.cpp 的 Win32WindowingSystem 类具体实现的,它创建的显示窗口设备osgViewer::GraphicsWindowWin32 的实例。
上面的内容还能理解,下面的就不知道在说什么了。就这样吧。
3、进一步深究的话,如果窗口特性(Traits)中开启了 pbuffer 选项,则 OSG 将尝试创建 osgViewer::PixelBufferWin32 设备,以实现离屏渲染(Offscreen Render),纹理烘焙(Render-To-Texture)等工作;否则只建立通常的 OpenGL 窗口。
真是令人兴奋!没错, GraphicsContext::makeCurrent 和 GraphicsContext:: releaseContext函数也是用相同的方法来实现多态性的,而它们的工作也就是 OpenGL 开发者使用函数wglMakeCurrent 完成的工作,将渲染上下文 RC 对应到正确的窗口绘制句柄上。