查看: 5100|回复: 7

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

[复制链接]

该用户从未签到

发表于 2008-8-15 11:03:43 | 显示全部楼层 |阅读模式
当前位置:osgViewer/Viewer.cpp第385行,osgViewer::Viewer::realize()
Viewer::realize函数是我们十分熟悉的另一个函数,从OSG问世以来,我们就习惯于在进入仿真循环之前调用它(现在的OSG会自动调用这个函数,如果我们忘记的话),以完成窗口和场景的“设置”工作。那么,什么叫做“设置”,这句简单的场景设置又包含了多少内容呢?艰辛的旅程就此开始吧。

首先是一行:setCameraWithFocus(0),其内容无非是设置类变量_cameraWithFocus指向的内容为NULL。至于这个“带有焦点的摄像机”是什么意思,我们似乎明白,似乎又不明白,就先放入一个“悬疑列表”(Todo List)中好了。

下面遇到的函数就比较重要了,因为我们将会在很多地方遇到它:
  1. Contexts contexts;
  2. getContexts(contexts);
复制代码
变量contexts是一个保存了osg::GraphicsContext指针的向量组,而Viewer::getContexts函数的作用是获取所有的图形上下文,并保存到这个向量组中来。

对于需要将OSG嵌合到各式各样的GUI系统(如MFC,Qt,wxWidgets等)的朋友来说,osg::GraphicsContext类是经常要打交道的对象之一。一种常用的嵌入方式也许是这样实现的:
  1. osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
  2. osg::ref_ptr<osg::Referenced> windata =
  3.   new osgViewer::GraphicsWindowWin32::WindowData(hWnd);
  4. traits->x = 0;
  5. traits->y = 0;
  6. ……
  7. traits->inheritedWindowData = windata;
  8. osg::GraphicsContext* gc = osg::GraphicsContext::createGraphicsContext(traits.get());
  9. Camera* camera = viewer.getCamera();
  10. camera->setGraphicsContext(gc);
  11. ……
  12. viewer.setCamera(camera);
复制代码
这个过程虽然比较繁杂,但是顺序还是十分清楚的:首先设置嵌入窗口的特性(Traits),例如X、Y位置,宽度和高度,以及父窗口的句柄(inheritedWindowData);然后根据特性的设置创建一个新的图形设备上下文(GraphicsContext),将其赋予场景所用的摄像机。而我们在getContexts函数中所要获取的,也许就包括这样一个用户建立的GraphicsContext设备。

当前位置:osgViewer/Viewer.cpp第1061行,osgViewer::Viewer::getContexts()
在这个函数之中,首先判断场景的主摄像机_camera是否包含了一个有效的GraphicsContext设备,然后再遍历所有的从摄像机_slaves(一个视景器可以包含一个主摄像级和多个从摄像机),将所有找到的GraphicsContext图形上下文设备记录下来。

随后,将这些GraphicsContext的指针追加到传入参数(contexts向量组)中,并使用std::sort执行了一步排序的工作,所谓的排序是按照这样的原则来进行的:
  • 1、屏幕数量较少的GraphicsContext设备排列靠前;
  • 2、窗口X坐标较小的设备排列靠前;
  • 3、窗口Y坐标较小的设备排列靠前。


如果希望观察自己的程序中所有的图形设备上下文,不妨使用这个函数来收集一下。简单的情形下,我们的程序中只有一个主摄像机,也就只有一个GraphicsContext设备,它表达了一个全屏幕的图形窗口;而osgcamera这个例子程序可以创建六个从摄像机,因此可以得到六个图形上下文设备,且各个图形窗口的X坐标各不相同,这也正是这个例子想要表达的。

可是,主摄像机的GraphicsContext呢?为什么osgcamera中不是七个GraphicsContext设备呢?答案很简单,主摄像机没有创建图形上下文,因此也就得不到设备的指针。为了理解这个现象的原因,我们不妨先回到realize函数中。

当前位置:osgViewer/Viewer.cpp第394行,osgViewer::Viewer::realize()
有一个显而易见的事实是:当程序还没有进入仿真循环,且对于osgViewer::Viewer还没有任何的操作之时,系统是不会存在任何图形上下文的;创建一个新的osg::Camera对象也不会为其自动分配图形上下文。但是,图形上下文GraphicsContext却是场景显示的唯一平台,系统有必要在开始渲染之前完成其创建工作。

假设用户已经在进入仿真循环之前,自行创建了新的Camera摄像机对象,为其分配了自定义的GraphicsContext设备,并将Camera对象传递给视景器,就像osgviewerMFC和osgcamera例子,以及我们在编写与GUI系统嵌合的仿真程序时常做的那样。此时,系统已经不必为图形上下文的创建作任何多余的工作,因为用户不需要更多的窗口来显示自己的场景了。所以就算主摄像机_camera还没有分配GraphicsContext,只要系统中已经存在图形上下文,即可以开始执行仿真程序了。

但是,如果getContexts没有得到任何图形上下文的话,就说明仿真系统还没有合适的显示平台,此时就需要尝试创建一个缺省的GraphicsContext设备,并再次执行getContexts,如果还是没能得到任何图形上下文的话,那么就不得不退出程序了。

创建缺省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的意义是什么?

[ 本帖最后由 array 于 2008-8-15 11:09 编辑 ]

该用户从未签到

发表于 2008-8-16 00:43:30 | 显示全部楼层
好帖没人来顶,难道要让楼主寒心?

该用户从未签到

发表于 2008-8-16 10:14:35 | 显示全部楼层
lz辛苦了~~

该用户从未签到

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

该用户从未签到

发表于 2008-8-21 11:33:21 | 显示全部楼层
太棒了,array,能否把相关的帖子集成在一起呀?期待

该用户从未签到

发表于 2008-8-28 23:09:15 | 显示全部楼层
谢谢,正在学习

[ 本帖最后由 teli 于 2008-8-28 23:14 编辑 ]

该用户从未签到

发表于 2008-9-27 11:12:30 | 显示全部楼层
好的很嘛;

该用户从未签到

发表于 2010-2-19 06:43:43 | 显示全部楼层
继续学习
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

联系我们

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