Chinaunix首页 | 论坛 | 博客
  • 博客访问: 20335
  • 博文数量: 16
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 170
  • 用 户 组: 普通用户
  • 注册时间: 2019-02-19 14:05
文章分类

全部博文(16)

文章存档

2019年(16)

我的朋友

分类: C/C++

2019-02-22 13:30:20

    qiyuan

    任何程序都是有生命的,是生命就需要呼吸。例如普通的windows程序,当运行完main()函数后,就需要进入消息循环,来监听用户的各种操作,以便做出及时的回应。这样的每次循环就像生命的每次呼吸,来维持生命体征。

    osg的程序不仅仅需要消息循环来监听用户的鼠标、键盘等操作,同时也得具备了渲染循环。当然随着我们的对osg的深入了解会发现,osg的事件监听和渲染循环是串行的。但是当我们把osg与MFC(QT)等结合时,相应UI上的鼠标,键盘事件的同时也要兼顾可能发生在osg中的效果,所以一般的osg程序起码需要两个并行的线程(例如osg与qt结合使用,为了保持足够灵敏的相应速度就需要把QTUI和osg渲染看成两种生命,分为两个线程)来维持它的正常运行。我们今天就是要解读osg程序赖以生存的每次呼吸。

    首先我们得找到osg是用什么呼吸的,就想地球上的一般生物都是用鼻子呼吸,我们又大概得知道鼻子长在生物的那个位置。这样我们才可以开始我们的研究。当然我们肯定得有osg的源码,就像我们研究生物的呼吸先得有这种生物的身体。有了身体我们还得持续的观察一个有生命的生物,所以我们最先得到osg的可运行的程序就是example中的各种程序。其中大部分的程序main()函数的最后部分都是调用一下viewer.run()。

    osgtext

    所以我们可以有一个模糊的判断这一类的通过调用viewer类的run函数的程序,他的呼吸系统可能是通过run完成的。但是run()函数是一个单独的一行,按说他执行完毕以后程序就会结束了,所以我们有了新的判断osg的每一帧的调用的入口是在run()函数中的。这是osg程序存在的一种形式(或者叫独立运行模式)。Osg还有另一种存在形式,就是和各种UI混合使用,例如qt与osg结合使用,MFC与osg结合使用等等。我们可以从examples/osgviewerQt 的例子,可以根据上一个的思路,呼吸不是一次性的动作,是只要存活就会一直存在的。所以从osgviewerQt.cpp中根据以前的经验定位到timer (计时器),他每次timeout触发时调用的函数update()中一定包含了osg的每一帧的调用的入口。

    osgviewer

    根据上面两种osg的存活形式,可以进行进一步的确认,究竟哪里才是维持osg生命体征的位置。Viewer.run()函数(OSG Core/osgViewer/Viewer.cpp)最后会继续调用ViewerBase::run()函数(OSG Core/osgViewer/ViewerBase.cpp),

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int Viewer::run()
    {
        if (!getCameraManipulator() && getCamera()->getAllowEventFocus())
        {
            setCameraManipulator(new osgGA::TrackballManipulator());
        }
     
        setReleaseContextAtEndOfFrameHint(false);
     
        return ViewerBase::run();
    }
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    int ViewerBase::run()
    {
        if (!isRealized())
        {
            realize();
        }
     
        const char* run_frame_count_str = getenv("OSG_RUN_FRAME_COUNT");
        unsigned int runTillFrameNumber = run_frame_count_str==0 ? osg::UNINITIALIZED_FRAME_NUMBER : atoi(run_frame_count_str);
     
        while(!done() && (run_frame_count_str==0 || getViewerFrameStamp()->getFrameNumber()
        {
            double minFrameTime = _runMaxFrameRate>0.0 ? 1.0/_runMaxFrameRate : 0.0;
            osg::Timer_t startFrameTick = osg::Timer::instance()->tick();
            if (_runFrameScheme==ON_DEMAND)
            {
                if (checkNeedToDoFrame())
                {
                    frame();
                }
                else
                {
                    // we don't need to render a frame but we don't want to spin the run loop so make sure the minimum
                    // loop time is 1/100th of second, if not otherwise set, so enabling the frame microSleep below to
                    // avoid consume excessive CPU resources.
                    if (minFrameTime==0.0) minFrameTime=0.01;
                }
            }
            else
            {
                frame();
            }
     
            // work out if we need to force a sleep to hold back the frame rate
            osg::Timer_t endFrameTick = osg::Timer::instance()->tick();
            double frameTime = osg::Timer::instance()->delta_s(startFrameTick, endFrameTick);
            if (frameTime < minFrameTime) OpenThreads::Thread::microSleep(static_cast(1000000.0*(minFrameTime-frameTime)));
        }
     
        return 0;
    }

    我们在ViewerBase::run()中继续耐心的寻找就会发现有一个特殊的函数frame(),为什么特殊呢?因为frame的英文的意思就是’帧’,而我们学渲染都知道’帧’代表屏幕上一幅画,这和osg库的本质就联系在了一起。Osg就是一个库,一个在计算机屏幕上作画的库。所以ViewerBase::frame()就是我们要找的osg中会呼吸的地方。同样我们在examples/osgviewerQt中也会发现,timer每到设定事件就会调用update()函数,而qt的update()函数在内部就会调用paintEvent()函数,我们在osgviewerQt.cpp的paintEvent()函数中也会发现osg::CompositeViewer的update函数,而osg::CompositeViewer继承自ViewerBase,所以最后也会定位到ViewerBase::frame()。这样我们就可以确定osg这类生物的呼吸的入口是ViewerBase::frame()函数。终于我们打开了通往新世界的大门,下一步就是经历轮回,看看osg这类生物是怎么生存的。


欢迎大家来我的新家看一看 
阅读(592) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~