当判断到viewer中没有一个graphicContext可用时,osg就会默认的进行一次对viewer的实现操作,这样可以保证osg以后可以安心的在屏幕上进行作画。那我们就来看看这个osgViewer::Viewer::realize()函数到底具备什么样神奇的功能。
osgViewer::Viewer::realize()
osgViewer::Viewer::realize()的最要作用可以总结为激活设置窗口以及初始化关联线程。Viewer::getContexts()上一节以及进行了详细的介绍,就是得到所有相机上关联的图形设备器。当contexts为空时就代表不存在一个窗口set up,所以osg开启默认一个的视图。读取环境变量OSG_CONFIG_FILE,如果设置了OSG_CONFIG_FILE指向一个.view后缀的文件,可以创建该文件描述的窗口,格式如下:(在openscenegraph-data目录中的configuration目录下有.view类型的文件)
osgViewer::Viewer
{
setUpViewInWindow 100 200 600 400 0
}
如果设置了OSG_CONFIG_FILE环境变量,但是环境变量所对应的文件解析有错,那么整个程序就会退出。
如果没有设置OSG_CONFIG_FILE环境变量,那么程序会检查 OSG_SCREEN和OSG_WINDOW这两个环境变量的值,OSG_SCREEN对应窗口的个数(值是一个整型数)OSG_WINDOW对应窗口的大小和位置,格式是(x, y, w, h) 分别是窗口左上角点坐标(x, y)以及窗口的长和宽(w, h),具体来说是以下情况:
当窗口设置完成之后,osg会再次调用getContexts(contexts) 搜集目前可用的设备渲染上下文,如果这时候还没有窗口产生,也就是说设置窗口的各种方式都失败了,那么程序就会退出,如果成功,那么会针对已经常见的窗口进行一些设置,完成后续的操作
接下来我们先简单的介绍一个表格中三个函数
这些函数调用了osgViewer命名空间中的三个窗口配置类,它们的关系如下图所示:
基类osgViewer::ViewConfig提供了一个虚函数 virtual void configure (osgViewer::View &) const,在子类中通过实现该函数来配置渲染的窗口大小和位置。
这里我们只对一个类的configure函数进行讲解,其他两个请大家自行了解。
AcrossAllScreens::configure(osgViewer::View& view)函数,首先调用osg::GraphicsContext的静态函数getWindowSystemInterface用于获得系统的api接口,至于这个api接口是怎么被创建的,我们需要在src/osg/GraphicsContext.cpp中找到setWindowSytemInterface函数,这里就是进行系统api的设置,他的作用是指定操作平台所使用的视窗 API 接口,也就是在特定的系统平台上创建图形窗口的时候,将会使用到哪些本地 API 函数。当然,Windows 系统要使用 Win32 API,而Linux 系统要使用 X11 API,Apple 系统则使用 Carbon。由于现在实在ubuntu16.04系统上,所以cmake只会把GraphicsWindowX11.cpp进行编译,所以想知道怎么指定的系统api接口在GraphicsContext中,我们需要进入GraphicsWindowX11.cpp的2136行的WindowingSystemInterface 结构体,这个结构体在初始化的时候就会调用。用于设置系统api接口。还 有 注 意 那 个 紧 跟 着 结 构 体 的 全 局 变 量(GraphicsWindowX11.cpp,2159 行),这就是osg设置系统api的基本流程,如果想深入了解,请自行查看。
回到AcrossAllScreens::configure(osgViewer::View& view)函数
osg::DisplaySettings
我们得到了系统api的指针,然后将尝试获取osg::DisplaySettings的指针,它保存了 OSG 目前用到的,与图形显示,尤其是立体显示有关的所有信息,
主要包括:
_displayType:显示器类型,默认为 MONITOR(监视器),此外还支持 POWERWALL(威力墙),REALITY_CENTER(虚拟实境中心)和 HEAD_MOUNTED_DISPLAY(头盔显示器)。
_stereoMode : 立 体 显 示 模 式 , 默 认 为 ANAGLYPHIC ( 互 补 色 ), 此 外 还 支 持QUAD_BUFFER (四方体缓冲), HORIZONTAL_SPLIT (水平分割), VERTICAL_SPLIT (垂直分割),LEFT_EYE(左眼用),RIGHT_EYE(右眼用),HORIZONTAL_INTERLACE(水平交错),VERTICAL_INTERLACE(垂直交错),CHECKERBOARD(棋盘式交错,用于DLP 显示器)。
_eyeSeparation:双眼的物理距离,默认为 0.05。
_screenWidth,_screenHeight:屏幕的实际宽度和高度,分别默认设置为 0.325 和 0.26,
目前它们影响的仅仅是视图采用透视投影时的宽高比。
_screenDistance:人眼到屏幕的距离,默认为 0.5。
_splitStereoHorizontalEyeMapping:默认为 LEFT_EYE_LEFT_VIEWPORT(左眼渲染左视口),也可设为 LEFT_EYE_RIGHT_VIEWPORT(左眼渲染右视口)。
_splitStereoHorizontalSeparation:左视口和右视口之间的距离(像素数),默认为 0。
_splitStereoVerticalEyeMapping:默认为 LEFT_EYE_TOP_VIEWPORT(左眼渲染顶视口),也可设为 LEFT_EYE_BOTTOM_VIEWPORT(左眼渲染底视口)。
_splitStereoVerticalSeparation:顶视口和底视口之间的距离(像素数),默认为 0。
_splitStereoAutoAdjustAspectRatio:默认为 true,用于屏幕分割之后对其宽高比进行补偿。
_maxNumOfGraphicsContexts:用户程序中最多可用的 GraphicsContext(图形设备上下文)数目,默认为 32 个。
_numMultiSamples:多重采样的子像素样本数,默认为 0。如果显示卡支持的话,打开多重采样可以大幅改善反走样(anti-aliasing)的效果。此外还有很多可以设置的类变量,如_minimumNumberStencilBits(模板缓存的最小位数)等,其默认设置均在 osg::DisplaySettings::setDefaults 函数中完成,其中有些变量可能还没有作用。要注意的是,DisplaySettings 的作用仅仅是保存所有可能在系统显示中用到的数据,这个类本身并不会据此改变任何系统设置和渲染方式。
再此回到AcrossAllScreens::configure(osgViewer::View& view)函数,我们上一节总结了一下osg::DisplaySettings的作用,我们继续看看配置一个osg内置的screen需要哪些设置。通过相机得到视椎体的一些信息(包含:fovy俯仰角,aspectRatio纵横比,zNear近平面, zFar远平面,其中这里用到的属性是aspectRatio,主要是用来确定当osg默认的与图形设备中设置的screen数目的相同的从相机中每一个从相机的视口的大小)。然后再通过ScreenIdentifier平面初始化器得到screenNum,displayNum,hostName的值。其中如果screenNum或displayNum未定义则设定为-1,这三个变量的最主要的作用是给GraphicsContext中的某些属性赋值。当displayNum的值是1,也就相当于创建一个SingleScreen,所以直接可以调用昨天提到的SingleScreen的configure函数,创建一个单独的屏幕来渲染三维世界就可以了,但是当displayNum的值大于1时,就需要用到分屏技术,通过创建多个从相机,来得到场景中的某一部分的视图,最后拼接成一个大的三维场景的方式。所以else(src\osgViewer\config\AcrossAllScreens.cpp\ AcrossAllScreens::configure 函数的第50行之后都是在创建多个GraphicsContext并付给相应的从相机。)
这样我们就介绍完了osg创建一种AcrossAllScreens的方式。
欢迎大家来我的新家看一看 3wwang个人博客-记录走过的技术之路