osg窗口的创建(二)

【OSG】将显示的图形窗口化 窗口化原理有时为了方便控制场景渲染,需要设置一个合适的图形环境窗口(即窗口化)。 创建图形环境的主要步骤如下: (1)通过WindowingSystemInterface类得到系统窗口接口,该系统接口主要是为了关联窗口系统与图形环境。 (2)下面是OSG中图形环境的主要特性,但在实际应用的过程中,没有必要设置每一个参数,只需根据实际需要来设置合理的参数即可。x,y,width,height;/ 阅读详情

本文接着osg窗口的创建(一)中关于GraphicsContext的内容继续阅读。

还是先看看GraphicsContext中的继承图


由于是在Windows平台下分析窗口的创建,因此本文选取Win32中的实现来探讨,其他平台的原理类似,只是在细节上稍有不同。

前文说到了 isRealized的实现,我们在看看实现过程:

GraphicsContext的isRealized实现如下:

 inline bool isRealized() const 
 { 
 	return isRealizedImplementation();
 } 

isRealizedImplementation函数在GraphicsContext中是一个纯虚函数,在GraphicsWindow中的实现仅仅打印出一个提示信息(等同于没实现),真正的实现在GraphicsWindowWin32之中,实现如下:

virtual bool GraphicsWindowWin32::isRealizedImplementation() const 
{ 
	return _realized; 
}
仅仅是返回一个标识,于是我们有理由认为在 realize函数中设置了该标识。(实际上确实是这样的,后续再realize代码中再分析)

继续看frame中的实现:

        if (!isRealized())
        {
            realize();
        }
可以看到如果没有设置好窗口(isRealized返回值为false),那么就调用 realize函数来设置窗口,事实上osg的窗口创建过程就是在realize函数中完成的,在代码调试中到断点越过realize函数体,可以在任务栏上看到新的窗口出现。realize的详细实现如下:

1. realize在ViewerBase中是纯虚函数

2. realize的具体实现在osgViewer::Viewer类中实现:

void Viewer::realize()
{
    Contexts contexts;
    getContexts(contexts);

    if (contexts.empty())
    {
        OSG_INFO<<"Viewer::realize() - No valid contexts found, setting up view across all screens."<<std::endl;
        const char* ptr = 0;
        if ((ptr = getenv("OSG_CONFIG_FILE")) != 0)
        {
            readConfiguration(ptr);
        }
        else
        {
            int screenNum = -1;
            if ((ptr = getenv("OSG_SCREEN")) != 0)
            {
                if (strlen(ptr)!=0) screenNum = atoi(ptr);
                else screenNum = -1;
            }

            int x = -1, y = -1, width = -1, height = -1;
            if ((ptr = getenv("OSG_WINDOW")) != 0)
            {
                std::istringstream iss(ptr);
                iss >> x >> y >> width >> height;
            }

            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;
    }

    unsigned int maxTexturePoolSize = osg::DisplaySettings::instance()->getMaxTexturePoolSize();
    if (_camera->getDisplaySettings()) maxTexturePoolSize = std::max(maxTexturePoolSize, _camera->getDisplaySettings()->getMaxTexturePoolSize());
    if (_displaySettings.valid()) maxTexturePoolSize = std::max(maxTexturePoolSize, _displaySettings->getMaxTexturePoolSize());

    unsigned int maxBufferObjectPoolSize = osg::DisplaySettings::instance()->getMaxBufferObjectPoolSize();
    if (_displaySettings.valid()) maxBufferObjectPoolSize = std::max(maxBufferObjectPoolSize, _displaySettings->getMaxBufferObjectPoolSize());
    if (_camera->getDisplaySettings()) maxBufferObjectPoolSize = std::max(maxBufferObjectPoolSize, _camera->getDisplaySettings()->getMaxBufferObjectPoolSize());

    for(Contexts::iterator citr = contexts.begin();
        citr != contexts.end();
        ++citr)
    {
        osg::GraphicsContext* gc = *citr;

        // set the pool sizes, 0 the default will result in no GL object pools.
        gc->getState()->setMaxTexturePoolSize(maxTexturePoolSize);
        gc->getState()->setMaxBufferObjectPoolSize(maxBufferObjectPoolSize);

        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());

    setUpThreading();

    if (osg::DisplaySettings::instance()->getCompileContextsHint())
    {
        int numProcessors = OpenThreads::GetNumberOfProcessors();
        int processNum = 0;

        for(unsigned int i=0; i<= osg::GraphicsContext::getMaxContextID(); ++i)
        {
            osg::GraphicsContext* gc = osg::GraphicsContext::getOrCreateCompileContext(i);

            if (gc)
            {
                gc->createGraphicsThread();
                gc->getGraphicsThread()->setProcessorAffinity(processNum % numProcessors);
                gc->getGraphicsThread()->startThread();

                ++processNum;
            }
        }
    }
}
函数体的实现代码相对较长,分段进行分析:

1. 首先收集当前视景器Viewer中相机的渲染上下文,代码和isRealized中的实现一样

2. 如果不存在渲染上下文,我们进入第一段if判断中,可以看到主要进行的工作如下:

  • 读取环境变量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),具体来说是以下情况:
Screen取值     Window中width和height取值窗口设置函数
大于或等于0长和宽都大于0setUpViewInWindow(x, y, width, height, screenNum)
小于0长和宽都大于0setUpViewInWindow(x, y, width, height)
大于0长和宽为0或者负值setUpViewOnSingleScreen(screenNum)

其他情况下窗口设置函数使用setUpViewAcrossAllScreens()

当窗口设置完成之后,osg会再次调用getContexts(contexts) 搜集目前可用的设备渲染上下文,如果这时候还没有窗口产生,也就是说设置窗口的各种方式都失败了,那么程序就会退出,如果成功,那么会针对已经常见的窗口进行一些设置,完成后续的操作

这三个函数的实现如下所示:

void View::setUpViewAcrossAllScreens()
{
    apply(new osgViewer::AcrossAllScreens());
}

void View::setUpViewInWindow(int x, int y, int width, int height, unsigned int screenNum)
{
    apply(new osgViewer::SingleWindow(x, y, width, height, screenNum));
}

void View::setUpViewOnSingleScreen(unsigned int screenNum)
{
    apply(new osgViewer::SingleScreen(screenNum));
}
这桑函数调用了osgViewer命名空间中的三个窗口配置类,它们的关系如下图所示:



基类osgViewer::ViewConfig提供了一个虚函数 virtual void  configure (osgViewer::View &) const,在子类中通过实现该函数来配置渲染的窗口大小和位置。

SingleScreen在实现过程中会调用SingleWindow来完成设置,AcrossAllScreen在未设置窗口的大小和显示屏数目的时候会被调用(一般就是我们默认使用osg的场景),那么它会调用SingleWindow来设置,在设置过程中会读取外接显示器的分辨率,产生一个全屏的窗口,代码如下:

//来自于osgViewer::SingleWindow::configure
    if (traits->width<=0 || traits->height<=0 ) 
    {
        osg::GraphicsContext::ScreenIdentifier si;
        si.readDISPLAY();

        // displayNum has not been set so reset it to 0.
        if (si.displayNum<0) si.displayNum = 0;

        si.screenNum = _screenNum;

        unsigned int width, height;
        wsi->getScreenResolution(si, width, height);
        if (traits->width<=0) traits->width = width;
        if (traits->height<=0) traits->height = height;
    }

下面继续realize后面的代码,在完成窗口参数的设置之后,后面的代码无非是一些关于OpenGL缓冲区对象的设置等,暂时与窗口无关。在此之后进入到for循环之中,这里面就是窗口设置的内容了,实现的内容是对所有的相机中的设备上下文进行检查,并真正的产生窗口,窗口的产生调用在

gc->realize();

我们查看一下它的实现:

bool GraphicsContext::realize()
{
    if (realizeImplementation())
    {
        return true;
    }
    else
    {
        return false;
    }
}
实现中调用了另一个函数,继续往下看,它与isRealizedImplementation函数类似,在GraphicsContext中是一个纯虚函数,在窗口系统中实现相应的代码:

bool GraphicsWindowWin32::realizeImplementation()
{
    if (_realized) return true;

    if (!_initialized)
    {
        init();
        if (!_initialized) return false;
    }

    if (_traits.valid() && (_traits->sharedContext.valid() || _traits->vsync || _traits->swapGroupEnabled))
    {
        // make context current so we can test capabilities and set up context sharing
        struct RestoreContext
        {
            RestoreContext()
            {
                _hdc = wglGetCurrentDC();
                _hglrc = wglGetCurrentContext();
            }
            ~RestoreContext()
            {
                wglMakeCurrent(_hdc,_hglrc);
            }
        protected:
            HDC      _hdc;
            HGLRC    _hglrc;
        } restoreContext;

        _realized = true;
        bool result = makeCurrent();
        _realized = false;

        if (!result)
        {
            return false;
        }

        // set up sharing of contexts if required
        GraphicsHandleWin32* graphicsHandleWin32 = dynamic_cast<GraphicsHandleWin32*>(_traits->sharedContext.get());
        if (graphicsHandleWin32)
        {
            if (!wglShareLists(graphicsHandleWin32->getWGLContext(), getWGLContext()))
            {
                reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to share OpenGL context", _traits->screenNum, ::GetLastError());
                return false;
            }
        }

        // if vysnc should be on then enable it.
        if (_traits->vsync)
        {
            setSyncToVBlank(_traits->vsync);
        }

        // If the swap group is active then enable it.
        if (_traits->swapGroupEnabled)
        {
            setSwapGroup(_traits->swapGroupEnabled, _traits->swapGroup, _traits->swapBarrier);
        }
    }

    if (_ownsWindow)
    {
        //
        // Bring the window on top of other ones (including the taskbar if it covers it completely)
        //
        // NOTE: To cover the taskbar with a window that does not completely cover it, the HWND_TOPMOST
        // Z-order must be used in the code below instead of HWND_TOP.
        // @todo: This should be controlled through a flag in the traits (topMostWindow)
        //

        if (!::SetWindowPos(_hwnd,
                            HWND_TOP,
                            _windowOriginXToRealize,
                            _windowOriginYToRealize,
                            _windowWidthToRealize,
                            _windowHeightToRealize,
                            SWP_SHOWWINDOW))
        {
            reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to show window", _traits->screenNum, ::GetLastError());
            return false;
        }

        if (!::UpdateWindow(_hwnd))
        {
            reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to update window", _traits->screenNum, ::GetLastError());
            return false;
        }
    }

    _realized = true;

    // make sure the event queue has the correct window rectangle size and input range
    getEventQueue()->syncWindowRectangleWithGraphcisContext();

    return true;
}
可以看到窗口的产生是在这个函数中,在Win32程序设计中的常用函数UpdateWindow与SetWindowPos就是在这里调用的,SetWindowPos最终将窗口Show出来,让我们在系统中可以看到创建好的场景。


osg学习(四十八)Windows Error #2000 Windows Error #2000: Win32WindowingSystem::OpenGLContext() - Unable to restore current OpenGL rendering context. Reason: 无效的像素格式。 执行完 osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("mb_tiles.earth",myReadOptions); 后再执行 QOpenGLFramebuffe 阅读详情

相关推荐

自定义OSG显示窗口大小的三种方法

OSG默认显示全屏,为了调试的方便,需要自己修改显示设置,现在提供三种方法。 第一种 这种比较简单,直接在viewer->realize()之后添加如下代码 //设置显示窗口的大小 osgViewer::GraphicsWindow *pWnd = dynamic_cast<osgViewer::GraphicsWindow*>(viewer->getCamera()->getGraphicsContext()); if (pWnd) { pWnd->s

qq_42570058的博客 3923

OSG 《最长的一帧》 学习笔记-frame(一)

frame()作为渲染函数,只有简单的一句,但是它的内部到底是怎样的呢,我会跟着《最长的一帧》一起慢慢学习。///////////////////////////////////////为frame()源码,后面会深入解析每一个变量,每一个函数的源码//////////////////////////void ViewerBase::frame()//frame的内部实现{     if(_don...

findgeneralgirl的博客 2012

OSG-Win32窗口显示osg

上一节是入门: OSG+VS2015+Win10配置win32控制台程序下使用osg 为了方便,在上一节中,我们使用VS创建了一个win32控制台程序,然后添加代码:写法一#include<osgViewer/Viewer>#include<osgDB/ReadFile>int main(int argc, char **argv){ osgViewer::Viewer viewer; vi

一蓑烟雨任平生 也无风雨也无晴 9557

osg 线程模型

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

weixin_30762087的博客 602

OSG基础教程(二)osg嵌入Qt窗口(兼容Qt5)

将osg嵌入Qt。

hongfei_163的博客 4428

一、QT中创建OSG项目运行实例,初步实现版本

一般osg在vs2019编译器运行,只要配置相应的环境就能正常运行,但是如果要在qt中运行需要自己手动配置类才能正常运行,以下是qt中运行osg的一个示例。

qq_43605401的博客 2414

VS下OSG嵌入QT指定窗口

VS下OSG嵌入QT指定窗口1.编译osgqt2.osg中绘制窗口3.osg嵌入qt指定窗口1.新建QT工程2.添加QT窗口部件3.osg嵌入QT 1.编译osgqt 忘记了,自己搜一下吧。记得当时是又改了cmake编译的。之前的源码没有osgqt工程。 2.osg中绘制窗口 在osg中用qt绘制窗口,即qt嵌入osg。 在osg源码当中有案例Examples osgviewerQt 直接复制过...

lemon_haha的博客 2637

OSG和OSGEarth嵌入到qt窗口的几种方式

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 OSG和OSGEarth嵌入到qt窗口的几种方式前言一、pandas是什么?二、使用步骤1.引入库2.读入数据总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。 提示:以下是本篇文章正文内容,下面案例可供参考 一、pandas是什么? 示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而

qq_38697743的博客 8593

osg窗口的创建(一)

使用osg时我们首先需要做的第一件事就是创建一个渲染窗口,当我们配置好一个osg的开发环境,一般会编写以下一段测试程序: [cpp] view plain copy #include    #include    #include       int main()   {       osg::ref_ptr viewer = new

JeckZ博客 770

osg相机(基础篇)

在计算机的三维世界中,相机如同我们的眼睛,捕捉眼前的每一副画面,反过来物体要能够被相机在指定的距离和角度下观看到,并通过屏幕像素绘制出来。 在这个过程中,物体的三维空间坐标需要经过好几层矩阵变换,最终转换到二维平面坐标,并通过像素呈现在屏幕中。我们将这几层矩阵变换过程简称为MVPW矩阵变换。 下面我们展开介绍MVPW具体内容 ~ 模型(Model) MVPW中的M是模型顶点在三维场景中的位置。 一...

lavanana的博客 7192

osg demo24 多窗口渲染

#include #include #include #include #include #include #include //实现多窗口渲染 void multipleWindowMultipleCameras(osgViewer::Viewer& viewer,bool multipleScreens) { osg::GraphicsContext::WindowingSy

analyst_yuci 1859

osg窗口的创建(三)

前面两篇文章的分析只是讲述了窗口创建过程,但是里面还有部分细节并没有涉及,本文接着介绍这些内容,并详细讲述如何将osg嵌入到常用的窗口系统中: 窗口的创建补充 在窗口创建过程中还有一个地方并没有讲述清楚,就是:为什么osg可以识别我想创建的窗口是Win32的?为什么它不会创建其他的窗口设备(如GraphicsWindowCocoa、GraphicsWindowX11)。

Frank的专栏 8819

OSG在Win32下窗口形成的过程

OSG窗口在Win32下形成的过程 Main函数创建全局变量,创建系统接口,识别平台(Win32,Linux,Apple),可获取系统的一些属性(如分辨率等);系统接口创建后,在run的时候会绘制当前帧Frame,如果没有图形上下文则创建上下文,在创建上下文的时候会创建窗口,获取创建窗口句柄即可对窗口属性设置。

周陽讀書 840

二 QT+OSG结合可视化-使用CompositeViewer

按照这个框架设置界面,按钮加了两个事件,用来添加可绘制体的;不一定非要按照这个框架,选QWidget组件就行。如果需要添加自己的可视化对象,可以在"绘制面"方法中写自己的方法就行。

qq_43605401的博客 1446

三维引擎实践 - OSG引擎窗口创建过程

以GraphicsWindowX11为例,在Linux上用这个窗口类,Windows上用GraphicsWindows32类。一个3D应用程序,要想显示渲染结果,首先要创建一个窗口,本节就分析下OSG源码中窗口创建的过程。二: OSG中的窗口类介绍。三:OSG窗口建立过程。

GPU全栈博主 1251

告别GUI点点点:Formality形式化验证的TCL脚本自动化实战(附完整脚本)

本文详细介绍了如何通过TCL脚本实现Formality形式化验证的全流程自动化,显著提升验证效率并降低错误率。内容涵盖脚本框架解析、参数化设计、验证报告生成及团队协作策略,特别适合芯片设计工程师摆脱传统GUI操作,实现300%以上的效率提升。

weixin_33737134的博客 283

洞若观火(二)osgQt库—OSG扩展库

osgQOpenGL是OSG的一个扩展库,通常与OSG一起使用。

qq_43572400的博客 2211

无人机避障——4DMmvRadar三维点云坐标转换到无人机坐标系(三)

无人机避障——4DMmvRadar三维点云坐标转换到无人机坐标系(三)

weixin_45390670的博客 1869
上一篇: osg窗口的创建(一)
下一篇: osg窗口的创建(三)
csxiaoshui
博客等级 码龄16年 873粉丝 158原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值