查看: 6730|回复: 18

请教:关于osg拣选、光照以及动态场景的几个疑问

[复制链接]

该用户从未签到

发表于 2008-11-6 16:37:18 | 显示全部楼层 |阅读模式
以前一直用opengl和ogre、crystal space引擎,因为发现osg更适合场景漫游类应用,最近准备切换到osg引擎。看了几天官网和osgchina教程(特别是array前辈《最长的一帧》系列),在Linux下checkout svn源码编译学习,总算对osg基本结构有了点认识。经过这段时间的学习有几个问题一直没得到解决,请各位前辈抽空指点一下:

1、一段LOD测试代码,装入几百个cow.osg的LOD模型(用osgconv转换),发现当全部节点都在视距外时拣选时间仍旧很长(客户机配置较低),同样的模型导入ogre、crystal space和irrlicht几个渲染引擎中测试超视距时拣选开销几乎没有,是否哪些参数还需要进一步设置?

2、复杂建筑室内场景帧率很低(相比crystal space测试),将场景导出.ive文件用osgviewer看了一下统计信息,进入四面密闭的空房间后多边形数量还是很高,好像拣选步骤没有正常发挥作用(相对ogre等引擎),想请教osg支持哪些culling策略(除了基本的视锥、背面裁减、小物体剔除),对室内场景是否有专门的场景管理器或剔除算法(比如portal等)?

3、DatabasePager可否使用自定义协议代替本地文件和http模式,比如从关系数据库压缩blob字段加载,远程数据的本地cache管理能否使用OSG_FILE_CACHE环境变量指定目录以外的方法实现?

4、以前的项目场景cache根据内存大小动态分配,改用DatabasePager+PagedLOD后发现似乎只能根据inactive时间和frame计数来实现场景换出、装入,造成了多余的数据加载开销(比如用户静立一段时间后转身就会引发新的io操作),能否设置成由用户程序根据内存占用率(或其他条件)决定何时释放节点数据(gl对象数据仍旧通过PagedLOD现有机制释放)?

5、osg支持哪些光照技术,因为客户机配置较低用动态光照速度太慢,能否在一个场景同时应用几个光照图并对其动态切换(比如增加一支灯或者隐藏一面墙后光照情况改变)?

6、osg自身的一部分例子(未用到shader)运行时模型全白但没有报错(另外一些例子报告纹理大小不是2的整数幂),客户机是非x86的嵌入式系统,显卡是ati的radeon系列8或16M显存开源驱动,支持open 1.2或1.3(opengl压缩纹理支持有bug)可以跑Linux下面的多数OpenGL游戏,请问osg对opengl版本有什么要求?

[[i] 本帖最后由 lifc 于 2008-11-6 17:07 编辑 [/i]]

该用户从未签到

 楼主| 发表于 2008-11-6 17:36:32 | 显示全部楼层
以目前的理解从数据库等非http、本地文件系统数据源加载可以通过定义自己的ReadWriter来实现,只是这种方式还是无法从根本上杜绝DatabasePager进行场景数据装载、卸载带来的额外开销。

该用户从未签到

发表于 2008-11-6 18:50:00 | 显示全部楼层
1、这个似乎不应该,也没有什么要设置的,如果您确信是通过StatHandler发现CULL过程耗时较长,那么可以检查一下您的加载和PagedLOD设置是否正确。DatabasePager只处理PagedLOD和ProxyNode的数据;
2、OSG目前还没有专用于室内场景的筛选算法,您可以考虑使用遮挡节点,OSG提供了遮挡物裁减的功能;
3、目前不可以,如果您有好的建议和规划,不妨在osg-users上提出;
4、使用DatabasePager的话,应该不可以;
5、使用Shader是最好的选择,目前应该没有直接的类可用;
6、OpenGL的版本不算很高,虽说OSG应该可以在1.3的版本上运行,但是很多功能应该无法正常加载,最好使用支持OpenGL 2.0的显示设备。

虽然您说的这些目前并没有好的解决方案,但是OSG还是有很多大规模数据加载和浏览的成功案例的,只是和您以往的开发经验难以对照。您不妨和论坛里一些比较有实际工程经验的朋友,例如FlySky,交流讨论一下。

该用户从未签到

 楼主| 发表于 2008-11-6 23:21:03 | 显示全部楼层
谢谢array前辈逐一答复!因为项目原因年初开始就对OSG产生了兴趣,但一直没时间仔细研究。最近新平台开始规划,非常希望能用上OSG,因为他的结构比以往用过的Ogre/CrystalSpace等渲染引擎都清晰,而且天生对海量数据提供了良好的支持。看过array的答复后我现在理解OSG的定位基本是以大型室外场景渲染为主,所以对室内场景(以及相关算法)支持力度可能相对较弱(相比几个游戏渲染引擎而言)。

关于问题1,为了测试场景剔除效率暂时只用到了LOD节点。因目标代码运行在非x86的嵌入式机载设备上所以测试配置都比较低,分别是:
AMD Athlon64 X2 5000+/4G/GeForce 6150SE整合显卡(开发机)
P3 1.13G/512M/GF2 MX400 64M/GF4 MX440 64M/ATI VE 64M(PC104工控板)
MIPS32/512M/ATI Mobility Radeon 7500 16M双头/ATI Mobility Rage Pro 8M(嵌入式系统)
后两个是自己设计的MIPS CPU嵌入式主板,CPU性能大概与P3 800相当。OSG版本为svn trunk分支(2008/11/02),编译器gcc 4.3.2,系统为Gentoo i386/Gentoo mips,NVIDIA全部使用官方驱动,ATI全部为开源驱动,Linux内核版本2.6.27。

#include "all.h" // 预编译头

/*
* 生成LOD模型
* export OSG_OPTIMIZER="DEFAULT"
* osgconv --compressed --compressed-arb --simplify .2 cow.osg cow_dot2.ive
* osgconv --compressed --compressed-arb --simplify .7 -O noTexturesInIVEFile cow.osg cow_dot7.ive
*/
static osg::Node* createCowLOD(int level) {
    static char fname[] = "cow_dot0.ive";

    fname[7] = '0'+level;
    osg::Node* node = osgDB::readNodeFile(fname);
    node->setDataVariance(osg::Object::STATIC);
    return node;
}

int main() {
    osgViewer::Viewer viewer;

    // 创建LOD节点
    osg::LOD* lod = new osg::LOD();
    lod->addChild(createCowLOD(7), 0.f, 250.f);
    lod->addChild(createCowLOD(2), 250.f, 1000.f);
    lod->setRangeMode(osg::LOD::DISTANCE_FROM_EYE_POINT);

    // 构建场景图
    osg::Group* root = new osg::Group();
    for (int i = 0; i < 500; i++) {
        osg::MatrixTransform* transform = new osg::MatrixTransform( osg::Matrix::translate((i%5) * 40, (i/5) * 40, 0) );
        transform->addChild(lod);
        root->addChild(transform);
    }

    // 保存场景
    osgDB::writeNodeFile(*root, "LodCow.ive");

    viewer.setSceneData(root);
    return viewer.run();
}

x86编译:
g++-4.3.2 -W -Wall -O2 -march=pentium3 -o LodCow LodCow.cc -losgViewer

MIPS编译:
g++-4.3.2-mips32 -EL -W -Wall -O2 -march=mips32 -o LodCow LodCow.cc -losgViewer

运行程序得到LodCow.ive(拉近才能看到牛群),全部测试osgviewer统计信息都显示最大开销在Cull步骤上(视野为空时),占用时间从6.x ms到4x ms不等,而且物体可见时Cull开销反而更小!Radeon显卡环境物体全部在视距外时Cull占用48 ms帧率18fps(比自己用OpenGL写的简陋引擎还慢),而相同环境的ogre帧率有261,x86体系测试结果也相似,大伙帮忙看看是啥毛病?

该用户从未签到

 楼主| 发表于 2008-11-6 23:29:56 | 显示全部楼层
2、OSG目前还没有专用于室内场景的筛选算法,您可以考虑使用遮挡节点,OSG提供了遮挡物裁减的功能;

我也觉得应该如此。当用osgviewer进入一个密闭空间“面壁思过”时面前的墙面(顶点着色,无材质贴图,每个面2个三角形)是否可以自然起到遮挡节点作用,或是需要另外创建不可见的遮挡节点(类似CrystalSpace引擎)?之前专门测试过这种情况,俯视整个小镇和进入中心建筑“面壁”osgviewer显示的顶点数和三角形数都是8xxx:1xxx,所以才怀疑自己的剔除设置有问题。

该用户从未签到

发表于 2008-11-7 01:17:59 | 显示全部楼层
看了你的写的代码,你的第一个问题应该是你把数据都写进一个LOD文件了,遮挡裁剪需要将所有数据送入管线的大部分阶段而影响了你的渲染效率,用PagedLOD就可以解决你的问题。OSG中有遮挡节点,是基于视点的遮挡裁剪,需要指定遮挡平面。如果你对场景遮挡裁剪有比较高的要求的话,可以进行单元遮挡裁剪的预处理,不过,单元遮挡裁剪的消耗是相当大的。目前,动态光照没有直接可用的类,array说的对,用shader最好了。好像在OpenGL1.3以后,具体的记不清楚了,取消对纹理是2的幂次的限制~~你更新一下驱动程序试试吧~~~

该用户从未签到

发表于 2008-11-7 01:21:48 | 显示全部楼层
原帖由 lifc 于 2008-11-6 23:29 发表

我也觉得应该如此。当用osgviewer进入一个密闭空间“面壁思过”时面前的墙面(顶点着色,无材质贴图,每个面2个三角形)是否可以自然起到遮挡节点作用,或是需要另外创建不可见的遮挡节点(类似CrystalSpace引擎) ...


这个你手动创建一个遮挡节点,,然后指定遮挡平面就可以了~~~~~

该用户从未签到

 楼主| 发表于 2008-11-7 02:18:37 | 显示全部楼层
原帖由 FlySky 于 2008-11-7 01:17 发表
看了你的写的代码,你的第一个问题应该是你把数据都写进一个LOD文件了,遮挡裁剪需要将所有数据送入管线的大部分阶段而影响了你的渲染效率,用PagedLOD就可以解决你的问题。

没想到这么晚还有高手在线:)最近一个星期才开始用业余时间研究osg,可能很多概念还不是很清楚。凭知觉上面“牛群”的代码当牛群没有进入可视范围或者观察者背向牛群时应该不会有数据送往GPU管线的,因为这时候osgviewer的统计结果显示顶点和多边形数量都为0。这种情况下LOD::traverse就应该非常高效的直接跳过这些“超视距”child节点才对 ...

该用户从未签到

 楼主| 发表于 2008-11-7 08:19:38 | 显示全部楼层
目前,动态光照没有直接可用的类,array说的对,用shader最好了

要能用shader是最好的,不过客户机硬件现没办法支持shader,只能用预先计算好的一个或多个lightmap做混合贴图,我再研究一下看看,似乎自己对材质做一次预处理也不算太麻烦...

该用户从未签到

 楼主| 发表于 2008-11-7 09:13:54 | 显示全部楼层
cull占用时间超长的问题今天晚回去编译一个profile版osg探测一下,之后会把结果贴上来给大家做个参考。

该用户从未签到

 楼主| 发表于 2008-11-7 17:32:35 | 显示全部楼层
用gprof对引擎进行分析,结果非常出人意料,主要开销居然在unref操作上面!之前用d语言+tango+derelict(d语言opengl接口)实现了现有的渲染引擎,因为d支持垃圾回收所以没有维护引用计数的开销,毕竟偶尔的回收比经常的引用计数维护要高效。

x86平台 OpenThreads库的OpenThreads::Atomic::operator++/operator--操作通过lock xadd $eax, _refCount实现效率尚且如此,MIPS下OpenThreads没有使用gcc builtin atomic结果就更加难看了。
下面是x86平台运行结果gprof输出:

$ gprof osgviewer

  %   cumulative   self              self     total         
time   seconds   seconds    calls  ms/call  ms/call  name   
52.72      0.49     0.49        3   163.43   163.43  osg::Referenced::unref() const
47.34      0.93     0.44                             osgDB::AuthenticationDetails::AuthenticationDetails(std::string const&,
std::string const&, osgDB::AuthenticationDetails::HttpAuthentication)
  0.00      0.93     0.00 199091995     0.00     0.00  data_start
  0.00      0.93     0.00        2     0.00     0.00  std::basic_string<char, std::char_traits<char>, std::allocator<char> >
std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::basic_string<char, std::char_traits<char>, std::allo
cator<char> > const&, char const*)
  0.00      0.93     0.00        1     0.00     0.00  global constructors keyed to main
  0.00      0.93     0.00        1     0.00   163.43  osg::ArgumentParser::~ArgumentParser()
  0.00      0.93     0.00        1     0.00     0.00  osgGA::KeySwitchMatrixManipulator::KeySwitchMatrixManipulator()
  0.00      0.93     0.00        1     0.00     0.00  osgUtil::Optimizer::~Optimizer()
  0.00      0.93     0.00        1     0.00     0.00  std::_Rb_tree<osg::Object const*, std::pair<osg::Object const* const, u
nsigned int>, std::_Select1st<std::pair<osg::Object const* const, unsigned int> >, std::less<osg::Object const*>, std::alloca
tor<std::pair<osg::Object const* const, unsigned int> > >::_M_erase(std::_Rb_tree_node<std::pair<osg::Object const* const, un
signed int> >*)
  0.00      0.93     0.00        1     0.00     0.00  std::_Rb_tree<std::string, std::pair<std::string const, osg::ArgumentPa
rser::ErrorSeverity>, std::_Select1st<std::pair<std::string const, osg::ArgumentParser::ErrorSeverity> >, std::less<std::stri
ng>, std::allocator<std::pair<std::string const, osg::ArgumentParser::ErrorSeverity> > >::_M_erase(std::_Rb_tree_node<std::pa
ir<std::string const, osg::ArgumentParser::ErrorSeverity> >*)

-----------------------------------------------
[1]     52.7    0.00    0.49                 main [1]
                0.33    0.00       2/3           osg::Referenced::unref() const [2]
                0.00    0.16       1/1           osg::ArgumentParser::~ArgumentParser() [4]
                0.00    0.00      49/199091995     data_start [5]
                0.00    0.00       2/2           std::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*) [9]
                0.00    0.00       1/1           osgGA::KeySwitchMatrixManipulator::KeySwitchMatrixManipulator() [11]
                0.00    0.00       1/1           osgUtil::Optimizer::~Optimizer() [12]
-----------------------------------------------
                0.16    0.00       1/3           osg::ArgumentParser::~ArgumentParser() [4]
                0.33    0.00       2/3           main [1]
[2]     52.7    0.49    0.00       3         osg::Referenced::unref() const [2]
                0.00    0.00 198776802/199091995     data_start [5]
-----------------------------------------------
                                                 <spontaneous>
[3]     47.3    0.44    0.00                 osgDB::AuthenticationDetails::AuthenticationDetails(std::string const&, std::string const&, osgDB::AuthenticationDetails::HttpAuthentication) [3]
-----------------------------------------------
                0.00    0.16       1/1           main [1]
[4]     17.6    0.00    0.16       1         osg::ArgumentParser::~ArgumentParser() [4]
                0.16    0.00       1/3           osg::Referenced::unref() const [2]
                0.00    0.00       1/1           std::_Rb_tree<std::string, std::pair<std::string const, osg::ArgumentParser::ErrorSeverity>, std::_Select1st<std::pair<std::string const, osg::ArgumentParser::ErrorSeverity> >, std::less<std::string>, std::allocator<std::pair<std::string const, osg::ArgumentParser::ErrorSeverity> > >::_M_erase(std::_Rb_tree_node<std::pair<std::string const, osg::ArgumentParser::ErrorSeverity> >*) [14]
-----------------------------------------------
                0.00    0.00       2/199091995     osgGA::KeySwitchMatrixManipulator::KeySwitchMatrixManipulator() [11]
                0.00    0.00      49/199091995     main [1]
                0.00    0.00  315142/199091995     osg::Object::~Object() [19]
                0.00    0.00 198776802/199091995     osg::Referenced::unref() const [2]
[5]      0.0    0.00    0.00 199091995         data_start [5]

[[i] 本帖最后由 lifc 于 2008-11-7 17:34 编辑 [/i]]

该用户从未签到

 楼主| 发表于 2008-11-7 17:38:48 | 显示全部楼层
OSG的代码结构比较清晰,特别是场景图组织方面。内部逻辑处理用了一些设计模式(比如Vistor)来实现,清晰的同时却带来了一定的额外开销。下面是任意时刻ctrl-c打断osgviewer程序时gdb输出的调用追踪,进一步印证前面gprof的性能分析结果,看过之后对osg的渲染、拣选流程有了更加深刻的了解。

#0  osg::Referenced::unref (this=0x9bd15e0) at /usr/src/OpenSceneGraph.svn/include/osg/Referenced:165
#1  0xa7e49de4 in osg::CullStack::pushModelViewMatrix (this=0x9a9fe3c, matrix=0x9bd15e0,
    referenceFrame=osg::Transform::RELATIVE_RF) at /usr/src/OpenSceneGraph.svn/include/osg/ref_ptr:33
#2  0xa7c05c24 in osgUtil::CullVisitor::apply (this=0x9a9fe08, node=@0x9b062e0)
    at /usr/src/OpenSceneGraph.svn/src/osgUtil/CullVisitor.cpp:1023
#3  0xa7ec46ba in osg::NodeVisitor::apply (this=0x9a9fe08, node=@0x9b062e0)
    at /usr/src/OpenSceneGraph.svn/src/osg/NodeVisitor.cpp:136
#4  0xa7eba448 in osg::MatrixTransform::accept (this=0x9b062e0, nv=@0x9a9fe08)
    at /usr/src/OpenSceneGraph.svn/include/osg/MatrixTransform:37
#5  0xa7e9f2a8 in osg::Group::traverse (this=0x9aad2c8, nv=@0x9a9fe08)
    at /usr/src/OpenSceneGraph.svn/src/osg/Group.cpp:62
#6  0xa7e40c46 in osg::NodeVisitor::traverse (this=0x9be1e20, node=@0x9aad2c8)
    at /usr/src/OpenSceneGraph.svn/include/osg/NodeVisitor:181
#7  0xa7c08727 in osgUtil::CullVisitor::handle_cull_callbacks_and_traverse (this=0x9a9fe08, node=@0x9be1e20)
    at /usr/src/OpenSceneGraph.svn/include/osgUtil/CullVisitor:298
#8  0xa7c060ec in osgUtil::CullVisitor::apply (this=0x9a9fe08, node=@0x9aad2c8)
    at /usr/src/OpenSceneGraph.svn/src/osgUtil/CullVisitor.cpp:999
#9  0xa7ea0478 in osg::Group::accept (this=0x9aad2c8, nv=@0x9a9fe08)
    at /usr/src/OpenSceneGraph.svn/include/osg/Group:38
#10 0xa7c873a2 in osgUtil::SceneView::cullStage (this=0x9a9ea98, projection=@0x9a9d060, modelview=@0x9a9d0e0,
    cullVisitor=0x9a9fe08, rendergraph=0x9a9fc68, renderStage=0x9a9fcb8, viewport=0x9b4dda0)
    at /usr/src/OpenSceneGraph.svn/src/osgUtil/SceneView.cpp:926
#11 0xa7c8a1c0 in osgUtil::SceneView::cull (this=0x9a9ea98)
    at /usr/src/OpenSceneGraph.svn/src/osgUtil/SceneView.cpp:792
#12 0xa7af8712 in osgViewer::Renderer::cull (this=0x9a9e320)
    at /usr/src/OpenSceneGraph.svn/src/osgViewer/Renderer.cpp:307
#13 0xa7b29372 in osgViewer::ViewerBase::renderingTraversals (this=0xaffaf178)
    at /usr/src/OpenSceneGraph.svn/src/osgViewer/ViewerBase.cpp:696
#14 0xa7b28569 in osgViewer::ViewerBase::frame (this=0xaffaf178, simulationTime=1.7976931348623157e+308)
    at /usr/src/OpenSceneGraph.svn/src/osgViewer/ViewerBase.cpp:608
#15 0xa7b288ca in osgViewer::ViewerBase::run (this=0xaffaf178)
    at /usr/src/OpenSceneGraph.svn/src/osgViewer/ViewerBase.cpp:580
#16 0xa7b1faf9 in osgViewer::Viewer::run (this=0xaffaf178)
    at /usr/src/OpenSceneGraph.svn/src/osgViewer/Viewer.cpp:322
#17 0x0804b3b5 in main (argc=2, argv=0x804e184)
    at /usr/src/OpenSceneGraph.svn/applications/osgviewer/osgviewer.cpp:156

[ 本帖最后由 lifc 于 2008-11-7 17:43 编辑 ]

该用户从未签到

 楼主| 发表于 2008-11-7 17:42:30 | 显示全部楼层
关于问题6:经过截取opengl调用证实场景物体全白确实是材质尺寸NPOT(Not power of two)问题所致,mesa+dri的开源驱动对radeon显卡没有提供GL_ARB_texture_non_power_of_two扩展支持,导致glTexImage2D调用出错(返回GL_INVALID_VALUE),重新缩放全部材质后问题解决。

该用户从未签到

发表于 2008-11-7 17:58:27 | 显示全部楼层
非常赞赏lifc的探索精神,相信您在三维仿真方面也有不少经验,希望您有时间在论坛上发表一些文章和教程文字,大家一起分享;也热切期盼您将自己工作中遇到的问题和希望改进的功能提交给我们或者osg-users,促进OSG以及各类仿真开发库的发展。

该用户从未签到

发表于 2008-11-8 13:11:38 | 显示全部楼层
lifc真是经验丰富人士 ~~~~~可以想象白发苍苍的爱因斯坦了,哈哈~~~~~~~有兴趣的话,欢迎你加入OsgChina团队,请发一份简历到zzuxp@163.com~~~~~~

有空多交流~~~~~~

该用户从未签到

发表于 2008-11-8 13:17:51 | 显示全部楼层
原帖由 lifc 于 2008-11-7 08:19 发表

要能用shader是最好的,不过客户机硬件现没办法支持shader,只能用预先计算好的一个或多个lightmap做混合贴图,我再研究一下看看,似乎自己对材质做一次预处理也不算太麻烦...


这个我用过,lightmipmap,,,效果一般吧,,,,还是没有shader的动态真实效果~~~~~~~~~~~~

该用户从未签到

 楼主| 发表于 2008-11-8 14:48:05 | 显示全部楼层
楼上的朋友可能误会了:)其实我本行是做嵌入式开发和视频编码,多数时间都在和处理器、驱动程序、操作系统还有一些算法打交道。因为客户对我们的系统有3D方面的需求所以做过一点点这方面的工作,但毕竟不是主要业务领域,所以对于3D领域研究还只停留在皮毛水平。
不过个人还是非常看好osg,相比之前接触的一些开源、商业渲染引擎它的设计更干净明快,封装层也恰到好处:看到类名、方法名就可以联想到对应的OpenGL函数或数据结构,而且对常用OpenGL扩展做了相应包装。加上osgDB实现的丰富插件,对各种常用格式都提供了不错的支持,配合delta3d的扩展则更是如虎添翼,衷心希望通过大家的共同努日后在此之上能有一番做为!

该用户从未签到

发表于 2008-11-9 00:28:06 | 显示全部楼层
哈哈哈,,原来是这样啊~~~~~~有空多交流~~~~~

该用户从未签到

 楼主| 发表于 2008-11-12 17:13:39 | 显示全部楼层
原帖由 FlySky 于 2008-11-7 01:17 发表
OSG中有遮挡节点,是基于视点的遮挡裁剪,需要指定遮挡平面。如果你对场景遮挡裁剪有比较高的要求的话,可以进行单元遮挡裁剪的预处理

前两天研究了一下,原来osg的两个例子osgoccluder和osgocclusionquery就演示了这方面技术的用法,只怪自己当初心急没仔细看:)
前者通过设置固定遮挡平面来辅助拣选逻辑剔除不可见物体,后者则用OcclusionQueryNode方式实现。和其他引擎相比似乎麻烦了一点,但整体可控性相对更高。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表