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();
updateTraversal();
renderingTraversals();
}

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 不得不退出运行了(连图形窗口都建立不起来,还玩什么)。

void View::setUpViewOnSingleScreen(unsigned int screenNum)
{
apply(new osgViewer::SingleScreen(screenNum));
}

sgViewer/Viewer.cpp 第 496 行,void Viewer::realize()

void Viewer::realize()
{
//OSG_INFO<<"Viewer::realize()"<<std::endl; Contexts contexts;
getContexts(contexts); if (contexts.empty())
{
OSG_INFO<<"Viewer::realize() - No valid contexts found, setting up view across all screens."<<std::endl; // no windows are already set up so set up a default view std::string value;
if (osg::getEnvVar("OSG_CONFIG_FILE", value))
{
readConfiguration(value);
}
else
{
int screenNum = -;
osg::getEnvVar("OSG_SCREEN", screenNum); int x = -, y = -, width = -, height = -;
osg::getEnvVar("OSG_WINDOW", x, y, width, height); if (osg::getEnvVar("OSG_BORDERLESS_WINDOW", x, y, width, height))
{
osg::ref_ptr<osgViewer::SingleWindow> sw = new osgViewer::SingleWindow(x, y, width, height, screenNum);
sw->setWindowDecoration(false);
apply(sw.get());
}
else if (width> && height>)
{
if (screenNum>=) setUpViewInWindow(x, y, width, height, screenNum);
else setUpViewInWindow(x,y,width,height);
}
else if (screenNum>=)
{
setUpViewOnSingleScreen(screenNum);
}
else
{
setUpViewAcrossAllScreens();
}
} getContexts(contexts);
} if (contexts.empty())
{
OSG_NOTICE<<"Viewer::realize() - failed to set up any windows"<<std::endl;
_done = true;
return;
} // get the display settings that will be active for this viewer
osg::DisplaySettings* ds = _displaySettings.valid() ? _displaySettings.get() : osg::DisplaySettings::instance().get();
osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface(); // pass on the display settings to the WindowSystemInterface.
if (wsi && wsi->getDisplaySettings()==) wsi->setDisplaySettings(ds); unsigned int maxTexturePoolSize = ds->getMaxTexturePoolSize();
unsigned int maxBufferObjectPoolSize = ds->getMaxBufferObjectPoolSize(); for(Contexts::iterator citr = contexts.begin();
citr != contexts.end();
++citr)
{
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); /*
首先是 GraphicsContext::realize 函数,实际上也就是 GraphicsContext::realizeImplementation 函数。
realizeImplementation 是纯虚函数吗?没错,回想一下第三日的内容,当我们尝试使用createGraphicsContext 来创建一个图形设备上下文时,系统返回的实际上是这个函数的值:
而正如我们历经千辛万苦所分析的那样,wsref 所指向的是平台相关的 API 接口类,也就是 Win32 API 的接口,也就是 GraphicsWindowWin32.cpp 中对应类的实例。换句话说,此时 WindowingSystemInterface:: createGraphicsContext 函数返回的值,也应当是派生自GraphicsContext 的具体类的实例!
正确,对于 Windows 用户来说,这个函数返回的恰恰是 GraphicsWindowWin32 的实例,而前文的 realizeImplementation 函数,正是 GraphicsWindowWin32::realizeImplementation。
*/
gc->realize(); if (_realizeOperation.valid() && gc->valid())
{
gc->makeCurrent(); (*_realizeOperation)(gc); gc->releaseContext();
}
} // attach contexts to _incrementalCompileOperation if attached.
if (_incrementalCompileOperation) _incrementalCompileOperation->assignContexts(contexts); bool grabFocus = true;
if (grabFocus)
{
for(Contexts::iterator citr = contexts.begin();
citr != contexts.end();
++citr)
{
osgViewer::GraphicsWindow* gw = dynamic_cast<osgViewer::GraphicsWindow*>(*citr);
if (gw)
{
gw->grabFocusIfPointerInWindow();
}
}
} // initialize the global timer to be relative to the current time.
osg::Timer::instance()->setStartTick(); // pass on the start tick to all the associated event queues
setStartTick(osg::Timer::instance()->getStartTick()); // configure threading.
setUpThreading(); if (osg::DisplaySettings::instance()->getCompileContextsHint())
{
for(unsigned int i=; i<= osg::GraphicsContext::getMaxContextID(); ++i)
{
osg::GraphicsContext* gc = osg::GraphicsContext::getOrCreateCompileContext(i); if (gc)
{
gc->createGraphicsThread();
gc->getGraphicsThread()->startThread();
}
}
}
#if 0
osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState();
if (getCamera()->getViewport())
{
osg::Viewport* viewport = getCamera()->getViewport();
eventState->setInputRange( viewport->x(), viewport->y(), viewport->x() + viewport->width(), viewport->y() + viewport->height());
}
else
{
eventState->setInputRange(-1.0, -1.0, 1.0, 1.0);
}
#endif
}

  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)。有兴趣的话不妨细细把玩一下。

这一节和王锐老师当时解读的osg版本源码差异性较大

文字参考:王锐老师《最长的一帧》
代码参考:OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield    (osg3.4)

osgViewer::View::setUpViewOnSingleScreen()的更多相关文章

  1. 《最长的一帧》 osg3.4 osgViewer::View::init() osgViewer::Viewer::getContexts()

    开始:osgViewer/ViewerBase.cpp   389行,startThreading()函数,启动线程   void ViewerBase::startThreading() { if ...

  2. osg osgViewer::View::setUpViewInWindow()

    void ViewerBase::frame(double simulationTime) { if (_done) return; // OSG_NOTICE<<std::endl< ...

  3. OSG-CompositeViewer

    原文连接地址:http://www.osgchina.org/index.php?Itemid=490&id=134:usecompositiv&option=com_content& ...

  4. osgViewer

    /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source ...

  5. Implementation Model Editor of AVEVA in OpenSceneGraph

    Implementation Model Editor of AVEVA in OpenSceneGraph eryar@163.com 摘要Abstract:本文主要对工厂和海工设计软件AVEVA的 ...

  6. OSG开发概览

    1 OSG基础知识 Ø OSG是Open Scene Graphic 的缩写,OSG于1997年诞生于以为滑翔机爱好者之手,Don burns  为了对滑翔机的飞行进行模拟,对openGL的库进行了封 ...

  7. osgEarth基础入门

    osgEarth基础入门 2015年3月21日 16:19 osgEarth是基于三维引擎osg开发的三维数字地球引擎库,在osg基础上实现了瓦片调度插件,可选的四叉树调度插件,更多的地理数据加载插件 ...

  8. OSG多屏显示问题

    // testMultiScreen.cpp : Defines the entry point for the console application.// #include "stdaf ...

  9. bullet_01

    #include <btBulletDynamicsCommon.h> #include <osgViewer/Viewer> #include <map> #in ...

随机推荐

  1. Nginx.conf配置文件默认配置块略解

    #user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #erro ...

  2. tensorflow与numpy的版本兼容性问题

    在Python交互式窗口导入tensorflow出现了下面的错误: root@ubuntu:~# python3 Python 3.6.8 (default, Oct 7 2019, 12:59:55 ...

  3. java.lang.AbstractMethodError: org.powermock.api.mockito.internal.mockmaker.PowerMockMaker.isTypeMockable

    [转]https://stackoverflow.com/questions/53539930/java-lang-abstractmethoderror-org-powermock-api-mock ...

  4. React Snippets 常用记录

    官网 PropTypes ptar→ PropTypes.array.isRequired ptor→ PropTypes.object.isRequired ptsr→ PropTypes.stri ...

  5. 一步一步使用webpack搭建项目

    MPA |-src |-main.js 项目打包的入口文件 |-App.vue 项目的根组件(项目一启动,见到的第一个页面) |-package.json 项目的描述文件,用于记录安装了哪些包 |-w ...

  6. HTML5 服务器发送事件(Server-Sent Events)

    沈阳SEO:HTML5 服务器发送事件(server-sent event)允许网页获得来自服务器的更新. Server-Sent 事件 - 单向消息传递 Server-Sent 事件指的是网页自动获 ...

  7. Neo4j数据进行备份、还原

    一.neo4j备份方式 neo4j数据库的备份还原分为两种: offline 和 online. Offline backup - dump Dump a database into a single ...

  8. 081_使用 awk 编写的 wc 程序

    #!/bin/bash#自定义变量 chars 变量存储字符个数,自定义变量 words 变量存储单词个数#awk 内置变量 NR 存储行数#length()为 awk 内置函数,用来统计每行的字符数 ...

  9. Atcoder Rating System

    来翻译一下官方文档,但是建议看英文原文,本文可能会出现一些错误,只是为了方便自己查阅用的. 对于你的每一场rated比赛,会有一个Performance值\(X_i\),你的rating是\(X_i- ...

  10. Python3循环

    Python中while语句的一般形式: while 判断条件: 语句 同样需要注意冒号和缩进,另外在Python中没有do…while循环 下面的实例计算1到100总和 ##calc.py n = ...