zoukankan      html  css  js  c++  java
  • 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)
  • 相关阅读:
    Spring Boot 使用 Dom4j XStream 操作 Xml
    Spring Boot 使用 JAX-WS 调用 WebService 服务
    Spring Boot 使用 CXF 调用 WebService 服务
    Spring Boot 开发 WebService 服务
    Spring Boot 中使用 HttpClient 进行 POST GET PUT DELETE
    Spring Boot Ftp Client 客户端示例支持断点续传
    Spring Boot 发送邮件
    Spring Boot 定时任务 Quartz 使用教程
    Spring Boot 缓存应用 Memcached 入门教程
    ThreadLocal,Java中特殊的线程绑定机制
  • 原文地址:https://www.cnblogs.com/herd/p/11110620.html
Copyright © 2011-2022 走看看