• osgViewer::View::setUpViewOnSingleScreen()


    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 = -1;
                osg::getEnvVar("OSG_SCREEN", screenNum);
    
                int x = -1, y = -1, width = -1, height = -1;
                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>0 && height>0)
                {
                    if (screenNum>=0) setUpViewInWindow(x, y, width, height, screenNum);
                    else setUpViewInWindow(x,y,width,height);
                }
                else if (screenNum>=0)
                {
                    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()==0) 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=0; 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)
  • 相关阅读:
    Splay模板(bzoj 1588)
    PDD----配对堆
    [BZOJ4025] 二分图 LCT/(线段树分治+并查集)
    FFT模板 生成函数 原根 多项式求逆 多项式开根
    [BZOJ4566][Haoi2016]找相同字符 后缀自动机+dp
    [BZOJ1503] [NOI2004]郁闷的出纳员 splay
    [loj#2566][BZOJ5333] [Sdoi2018]荣誉称号 树形dp
    [BZOJ4824][Cqoi2017]老C的键盘 树形dp+组合数
    [BZOJ5305][Haoi2018]苹果树 组合数
    [BZOJ2669][cqoi2012]局部极小值 状压dp+容斥原理
  • 原文地址:https://www.cnblogs.com/herd/p/11110620.html
Copyright © 2020-2023  润新知