浅谈osgViewer::StatsHandler、osg::Stats类的用法

本文介绍了osgViewer库中的StatsHandler类和osg::Stats类在视景器性能调试中的使用方法。StatsHandler用于在屏幕上显示统计信息,如帧率、事件处理时间等,而osg::Stats则收集和存储这些详细数据。用户可以通过设置不同的按键触发不同级别的信息显示,并能将统计信息输出到控制台。文章还详细讲解了相关接口的用法和统计参数的含义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1. 前言

2. osgViewer::StatsHandler

2.1. 功能与用法说明

2.2. 主要接口说明

3. osg::Stats

4. 附录


1. 前言

       osg为视景器的使用和调试提供了丰富的辅助组件,它们主要是以osg::ViewerBase的成员变量或交互事件处理器(osgGA::GUIEventHandler)的形式出现。osgViewer::StatsHandler、osg::Stats类就是其中的两个经常用到的辅助组件。

2. osgViewer::StatsHandler

2.1. 功能与用法说明

      osgViewer::StatsHandler类的头文件位于osg源码目录下的:

include\osgViewer\ViewerEventHandlers

文件; osgViewer::StatsHandler类的cpp文件位于osg源码目录下的:

src\osgViewer\StatsHandler.cpp

        该类的功能为向视景器osgViewer::Viewer(单视图)或osgViewer::CompositeViewer(多视图)输出屏幕统计信息。如下代码:

#include<osgViewer/Viewer>
#include<osgDB/readFile>
#include<osgViewer/ViewerEventHandlers>

int main(int argc, char* argv[])
{
    osg::ArgumentParser arguments(&argc, argv);
    osg::setNotifyLevel(osg::INFO);
    osgViewer::Viewer viewer(arguments);
    auto pNode = osgDB::readNodeFile(R"(E:\osg\OpenSceneGraph-Data\cow.osg)");
    if (nullptr == pNode)
    {
        OSG_WARN << "file not exist!\r\n";
        return 1;
    }

    auto pStatsEventHandler = new osgViewer::StatsHandler; // 构造一视景器统计事件处理器
    viewer.addEventHandler(pStatsEventHandler);  // 向视景器增加统计事件处理器
    viewer.setSceneData(pNode);
    return viewer.run();
}

为视景器对象viewer增加了一个pStatsEventHandler的统计事件处理器对象。一旦程序运行起来,默认情况下,第1次按小写s键,则只统计帧率,如下:

图1 

第2次按小写s键时,保持第1次按下s键的信息外,还统计和视景器相关的信息,如下:

图2 

当3次按下小写s键时, 保持第1、2次按下s键的信息外,还所有相机和场景相关的信息,如下:

图3 

 当4次按下小写s键时, 保持第1、2、3次按下s键的信息外,还统计所有视景器和场景相关的信息,如下:

图4

       当5次按下小写s键时,则清除图1到图4的所有输出信息,程序保证按下s的次数不会超过5,当达到5时,自动回到0,然后每次按下小写s键,自动加1,递增到5。按下大写S时,则将统计信息输出到标准控制台窗口。一个综合统计图如下所示:

图5

上述统计的信息主要信息说明如下:

参    数   名       参   数   含   义   备                                          注
Frame Rate 当前帧率在debug模式下为DEBUG Frame Rate
ThreadingModel线程模式ViewerBase::ThreadingModel枚举类型
Event一帧内交互事件耗费的时间单位:秒
Update一帧内场景更新耗费的时间单位:秒
Cull一帧内场景裁剪耗费的时间单位:秒
Draw渲染一帧耗费的时间单位:秒
GPU渲染一帧时,GPU耗费的时间单位:秒
Drawable场景内独立可绘制体总数
Geode场景内独立可绘叶节点总数
Vertices场景内独立顶点总数
Primitives场景内独立可图元数

                                                                                     表1 

因为统计的参数很多,其它参数含义请参见StatsHandler.cpp类源码。

2.2. 主要接口说明

osgViewer::StatEventHandler类主要接口说明如下:

void setKeyEventTogglesOnScreenStats(int key);
int getKeyEventTogglesOnScreenStats() const; 

上述接口功能为:设置或获取统计信息输出到屏幕的按键,默认为小写的s,可以设置为其它键,参数key是osgGA::GUIEventAdapter::KeySymbol枚举,即键盘虚拟码。如下将默认的小写s键改为数字0键作为统计信息的输出按下,此时按下0才能输出统计信息,s不再其作用:

auto pStatsEventHandler = new osgViewer::StatsHandler; // 构造一视景器统计事件处理器
pStatsEventHandler ->setKeyEventTogglesOnScreenStats(osgGA::GUIEventAdapter::KEY_0);

 下面接口:

void setKeyEventPrintsOutStats(int key);
int getKeyEventPrintsOutStats() const ;

功能为:设置或获取统计信息输出到控制台窗口的按键,同上面的类似,不再赘述。

void reset();

上面接口功能为:重置统计信息,此时界面上不会有任何统计信息。注意和按下默认的s键或设定的统计信息键累计5次不输出统计信息的不同:重置是将用于输出统计信息的相机的图形设备上下文对象及相机孩子对象都清空,这样会释放内存,而后者则不会。

3. osg::Stats

         视景器osgViewer::Viewer(单视图)或osgViewer::CompositeViewer(多视图)对象(为了便于后文描述,暂称为viewer)可以通过setViewerStats函数设置统计类对象。如下代码设置osg::Stats对象到视景器:

osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
auto pStats = new osg::Stats("test"); // 构造一个统计类对象,参数为统计类对象名称,最好根据业务需求取名
pStats->collectStats("scene", true);  // 统计场景数据。如果设置为false,则场景有关的数据不统计
viewer->setViewerStats(pStats); // 将统计类对象设置到视景器。


...... // 其它代码

viewer->run();

在执行视景器的run函数时会进入到ViewerBase类的renderingTraversals函数,在该函数中统计了相关信息,如下:

void ViewerBase::renderingTraversals()
{
    ...... // 其它代码略

    // 如果为视景器设置了统计对象且需要统计场景类的各种属性
    if (getViewerStats() && getViewerStats()->collectStats("scene"))
    {

        Views views;
        getViews(views);
        for(Views::iterator vitr = views.begin();
            vitr != views.end();
            ++vitr)
        {
            View* view = *vitr;
            osg::Stats* stats = view->getStats();
            osg::Node* sceneRoot = view->getSceneData();
            if (sceneRoot && stats)
            {
                osgUtil::StatsVisitor statsVisitor;
                sceneRoot->accept(statsVisitor);
                statsVisitor.totalUpStats();

                unsigned int unique_primitives = 0;
                osgUtil::Statistics::PrimitiveCountMap::iterator pcmitr;
                for(pcmitr = statsVisitor._uniqueStats.GetPrimitivesBegin();
                    pcmitr != statsVisitor._uniqueStats.GetPrimitivesEnd();
                    ++pcmitr)
                {
                    unique_primitives += pcmitr->second;
                }

                stats->setAttribute(frameNumber, "Number of unique StateSet", static_cast<double>(statsVisitor._statesetSet.size()));
                stats->setAttribute(frameNumber, "Number of unique Group", static_cast<double>(statsVisitor._groupSet.size()));
                stats->setAttribute(frameNumber, "Number of unique Transform", static_cast<double>(statsVisitor._transformSet.size()));
                stats->setAttribute(frameNumber, "Number of unique LOD", static_cast<double>(statsVisitor._lodSet.size()));
                stats->setAttribute(frameNumber, "Number of unique Switch", static_cast<double>(statsVisitor._switchSet.size()));
                stats->setAttribute(frameNumber, "Number of unique Geode", static_cast<double>(statsVisitor._geodeSet.size()));
                stats->setAttribute(frameNumber, "Number of unique Drawable", static_cast<double>(statsVisitor._drawableSet.size()));
                stats->setAttribute(frameNumber, "Number of unique Geometry", static_cast<double>(statsVisitor._geometrySet.size()));
                stats->setAttribute(frameNumber, "Number of unique Vertices", static_cast<double>(statsVisitor._uniqueStats._vertexCount));
                stats->setAttribute(frameNumber, "Number of unique Primitives", static_cast<double>(unique_primitives));

                unsigned int instanced_primitives = 0;
                for(pcmitr = statsVisitor._instancedStats.GetPrimitivesBegin();
                    pcmitr != statsVisitor._instancedStats.GetPrimitivesEnd();
                    ++pcmitr)
                {
                    instanced_primitives += pcmitr->second;
                }

                stats->setAttribute(frameNumber, "Number of instanced Stateset", static_cast<double>(statsVisitor._numInstancedStateSet));
                stats->setAttribute(frameNumber, "Number of instanced Group", static_cast<double>(statsVisitor._numInstancedGroup));
                stats->setAttribute(frameNumber, "Number of instanced Transform", static_cast<double>(statsVisitor._numInstancedTransform));
                stats->setAttribute(frameNumber, "Number of instanced LOD", static_cast<double>(statsVisitor._numInstancedLOD));
                stats->setAttribute(frameNumber, "Number of instanced Switch", static_cast<double>(statsVisitor._numInstancedSwitch));
                stats->setAttribute(frameNumber, "Number of instanced Geode", static_cast<double>(statsVisitor._numInstancedGeode));
                stats->setAttribute(frameNumber, "Number of instanced Drawable", static_cast<double>(statsVisitor._numInstancedDrawable));
                stats->setAttribute(frameNumber, "Number of instanced Geometry", static_cast<double>(statsVisitor._numInstancedGeometry));
                stats->setAttribute(frameNumber, "Number of instanced Vertices", static_cast<double>(statsVisitor._instancedStats._vertexCount));
                stats->setAttribute(frameNumber, "Number of instanced Primitives", static_cast<double>(instanced_primitives));
           }
        }
    }
 
...... // 其它代码略

其中以"Number of"开头的是被统计的属性名称,可以看成是对前文表1和后文表2的补充。

      获取视景器的osg::Stats对象如下:

viewer.getViewerStats();

然后使用osg::Stats对象的如下接口设置或获取指定帧索引下指定属性名的属性值:

bool setAttribute(unsigned int frameNumber, const std::string& attributeName, double value);
inline bool getAttribute(unsigned int frameNumber, const std::string& attributeName, double& value) const;

如下为获取第100帧时的帧速率:

double frameRate;
viewer.getViewerStats()->getAttribute(100, "Frame rate", frameRate);

这两个函数第2个参数表示的主要属性名如下表所示:

          属性名含                      义
Frame rate帧率
Event traversal time taken一帧内交互事件耗费的时间(单位:秒)
Update traversal time taken更新场景一帧耗费时间(单位:秒)
Cull traversal time taken一帧内场景裁剪耗费的时间(单位:秒)
GPU draw time taken渲染一帧时,GPU耗费的时间(单位:秒)
Draw traversal time taken场景内独立可绘制体总数
Number of unique Geode场景内独立的叶节点总数
Reference time系统运行事件(单位:秒)
Number of unique Geometry场景内独立几何体总数
Number of unique Vertices场景内独立顶点总数
Number of unique Primitives场景内独立图元总数

表2 

因为统计的参数很多,其它参数含义请参见StatsHandler.cpp类源码。其实osgViewer::StatEventHandler类内部就是通过osg::Stats类来实现统计信息的。

4. 附录

更多关于osg::Stats类用法请参考:osg::Stats类用法及该类源码剖析

osg其它事件处理器用法参见如下博文:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值