查看: 3881|回复: 4

OSG原创教程:最长的一帧(4)

[复制链接]

该用户从未签到

发表于 2008-8-17 14:17:19 | 显示全部楼层 |阅读模式
当前位置:osgViewer/Viewer.cpp第426行,osgViewer::Viewer::realize()
setUpViewOnSingleScreen和setUpViewAcrossAllScreens函数的实现流程与上一日介绍的setUpViewInWindow区别不是很大。值得注意的是,setUpViewAcrossAllScreens函数中调用GraphicsContext::getWindowingSystemInterface函数取得了与平台相关的视窗API接口类(其中的原理请参看上一日的文字),并进而使用WindowingSystemInterface::getNumScreens函数取得了当前系统的显示屏幕数。

事实上,如果我们需要在自己的程序中获取屏幕分辨率,或者设置屏幕刷新率的话,也可以使用同样的方法,调用getScreenResolution,setScreenResolution和setScreenRefreshRate等相关函数即可。具体的实现方法可以参见GraphicsWindowWin32.cpp的源代码。

setUpViewAcrossAllScreens函数可以自行判断屏幕的数量,并且使用多个从摄像机来对应多个屏幕的显示(或者使用主摄像机_camera来对应单一屏幕)。此外它还针对水平分割显示(HORIZONTAL_SPLIT)的情况,对摄像机的左/右眼设置自动做了处理,有兴趣的读者不妨仔细研究一下。

最后,本函数还执行了一个重要的工作,即View::assignSceneDataToCameras,这其中包括以下几项工作:
  • 1、对于场景漫游器_cameraManipulator,执行其setNode函数和home函数,也就是设置漫游器对应于场景图形根节点,并回到其原点位置。不过在我们使用setCameraManipulator函数时也会自动执行同样的操作。
  • 2、将场景图形赋予主摄像机_camera,同时设置它对应的渲染器(Renderer)的相关函数。这里的渲染器起到了什么作用?还是先放到悬疑列表中吧,不过依照我们的解读速度,这个问题可能会悬疑很久。
  • 3、同样将场景图形赋予所有的从摄像机_slaves,并设置每个从摄像机的渲染器。
  • 终于可以回到realize函数的正轨了,还记得下一步要做什么吧?对,在尝试设置了缺省的GraphicsContext设备之后,我们需要再次使用getContexts来获取设备,如果还是不成功的话,则OSG不得不退出运行了(连图形窗口都建立不起来,还玩什么)。


当前位置:osgViewer/Viewer.cpp第446行,osgViewer::Viewer::realize()
现在我们遍历所得的所有GraphicsContext设备(通常情况下,其实只有一个而已)。对于每个GraphicsContext指针gc,依次执行:
  1. gc->realize();
  2. if (_realizeOperation.valid() && gc->valid())
  3. {
  4.   gc->makeCurrent();
  5.   (*_realizeOperation)(gc);
  6.   gc->releaseContext();
  7. }
复制代码
一头雾水,但是决不能轻言放弃。仔细研究一下吧,首先是GraphicsContext::realize函数,实际上也就是GraphicsContext::realizeImplementation函数。
realizeImplementation是纯虚函数吗?没错,回想一下第三日的内容,当我们尝试使用createGraphicsContext来创建一个图形设备上下文时,系统返回的实际上是这个函数的值:
  1. ref_ptr<GraphicsContext::WindowingSystemInterface> &wsref = windowingSystemInterfaceRef();
  2. return wsref->createGraphicsContext(traits);
复制代码
而正如我们历经千辛万苦所分析的那样,wsref所指向的是平台相关的API接口类,也就是Win32 API的接口,也就是GraphicsWindowWin32.cpp中对应类的实例。换句话说,此时WindowingSystemInterface:: createGraphicsContext函数返回的值,也应当是派生自GraphicsContext的具体类的实例!

正确,对于Windows用户来说,这个函数返回的恰恰是GraphicsWindowWin32的实例,而前文的realizeImplementation函数,正是GraphicsWindowWin32::realizeImplementation。

晕头转向了……那么,用一张图也许能解决一点问题吧:
见附图1

  • 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对应到正确的窗口绘制句柄上。

如果您还想要深究具体的实现方法的话,就好好地阅读GraphicsWindowWin32.cpp中的相关内容吧,不过我们的旅程要继续了。

等等,刚才那段程序里面,_realizeOperation是什么,它又执行了什么?嗯,简单说来,这个变量是通过ViewerBase::setRealizeOperation来设置的,其主要作用是在执行realize函数时,顺便完成用户指定的一些工作。您自己的工作内容可以通过继承osg::Operation类,并重载operator()操作符来添加。osgcatch这个妙趣横生的例子(一个傻娃娃接玩具的小游戏)中就使用了setRealizeOperation,主要的作用是为场景中的Drawable几何对象立即编译显示列表(Display List)。有兴趣的话不妨细细把玩一下。

解读成果:
osgViewer::View::setUpViewOnSingleScreen,
osgViewer::View::assignSceneDataToCameras,osgViewer::View::setUpViewAcrossAllScreens。
悬疑列表:
类变量_cameraWithFocus的意义是什么?渲染器(Renderer)类起到什么作用?

附图1

附图1

该用户从未签到

发表于 2008-8-17 19:50:19 | 显示全部楼层
写的太好了!!
感谢LZ无私的讲解,有种当年MFC深入浅出的感觉!

该用户从未签到

发表于 2008-8-21 08:48:28 | 显示全部楼层
好贴,高水平的好贴
堪比MFC深入浅出
感谢楼主
尽快出书《OSG深入浅出》哈

该用户从未签到

发表于 2008-9-4 08:37:07 | 显示全部楼层
版主的刻苦研究精神非常值得学习!!!!

该用户从未签到

发表于 2008-9-27 11:26:39 | 显示全部楼层
我很欣慰;
我看到第四了;
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表