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. windows 数据备份

    xcopy 数据目录   备份目录  /e /c /q /h /r /y at 00:00 /every:M,T,W,Th,F,S,Su d:\批处理文件名

  2. Spring Cloud 之 全局配置

    在微服务架构中,全局配置的重要性不言而喻.SpringCloud的全局配置存储主要基于 Git 来实现,即配置信息存储在Git服务器,以统一的方式对外提供访问.在使用上分为 ConfigServer和 ...

  3. ubuntu18 搭建ftp服务器,以及文件目录权限问题

    有时候呢我们有一台本地的台式机或者云服务器,我们想要搭个ftp服务器好让我们在内网/外网中方便的传输.保存文件,这样别的任何电脑啊,设备啊,只要访问这个ftp的地址,就可以进行文件传输啦!由于我现在台 ...

  4. Codeforces 1206 D - Shortest Cycle

    D - Shortest Cycle 思路:n大于某个值肯定有个三元环,否则floyd找最小环. 代码: #pragma GCC optimize(2) #pragma GCC optimize(3) ...

  5. 前端学习笔记--CSS布局--盒子模型

    1.概述: 2.盒子模型 overflow属性: border属性: 1.padding属性: margin:

  6. h5触摸事件-判断上下滑动

    // 判断上下滑动 var startX = 0, startY = 0; function touchStart(evt){ try{ var touch = evt.touches[0], //获 ...

  7. Django --- 路由层(urls)

    目录 1.orm表关系如何建立 2.django请求生命周期流程图 3.urls.py路由层 4.路由匹配 5.无名分组 6.有名分组 7.反向解析 8.路由分发 9.名称空间 10.伪静态 11.虚 ...

  8. Time Intersection

    Description Give two users' ordered online time series, and each section records the user's login ti ...

  9. React组件属性/方法/库属性

    1. propTypes 用于进行props的类型检查:来自于prop-types库. // V15.5之后 import PropTypes from 'prop-types'; 该方法适用于函数组 ...

  10. WCF wsHttpBinding in SoapUI

    当使用wsHttpBinding,而不是平时用的webHttpBinding的时候,用soapui会报错.这个时候需要选中WS-A选项中的"Add default wsa:Action&qu ...