OSG 使用整理(2):设置渲染状态

发布时间 2023-04-15 18:29:15作者: 王小于的啦

二、场景管理

2.1 遍历场景图

  场景图遍历类型有以下几种:

  (1)     事件遍历:在遍历节点时,处理鼠标和键盘输入。

  (2)     更新遍历:用于修改场景图,添加节点,设置节点属性,执行回调。

  (3)     裁剪遍历:根据节点是否位于一个视口内来筛选节点,裁剪掉不可见和不可用的节点。

  (4)     绘制遍历:调用OpenGL API 来渲染场景。

  1 osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
  2 if ( cv )
  3 {
  4     // Do something
  5 }

  访问者模式用来表示在一个图结构上所执行的用户操作,而无需修改这些元素的类。访问者模式依据接收者元素与访问者本身的运行时类型,分派一定的虚函数调用。我们可以自定义访问者来来遍历场景图,无需修改场景节点的接口。要创建一个访问者子类,必须重新实现osg::NodeVisitor基类中所声明的一个或多个apply()虚重载方法。这些方法是为大多数主要的OSG节点类型所设计的。访问者会在遍历过程中为他所访问的每一个节点自动调用相应的apply()方法。自定义apply方法中,我们需要在合适的位置调用osg::NodeVisitor的traverse()方法,自动访问到其他节点。示例为自定义访问者收集节点信息。

 1 #include <osgDB/ReadFile>
 2 #include <osgViewer/Viewer>
 3 #include <iostream>
 4 class InfoVisitor : public osg::NodeVisitor
 5 {
 6 public:
 7     InfoVisitor() : _level(0)
 8     { setTraversalMode(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN); }
 9 
10     std::string spaces()
11     { return std::string(_level*2, ' '); }
12 
13     Virtual void apply( osg::Node& node );
14     virtual void apply( osg::Geode& geode );
15 
16 protected:
17     unsigned int _level;
18 };
19 void InfoVisitor::apply( osg::Node& node )
20 {
21     std::cout << spaces() << node.libraryName() << "::"
22       << node.className() << std::endl;
23 
24     _level++;
25     traverse( node );
26     _level--;
27 }
28 void apply( osg::Geode& geode )
29 {
30     std::cout << spaces() << geode.libraryName() << "::"
31       << geode.className() << std::endl;
32 
33     _level++;
34     for ( unsigned int i=0; i<geode.getNumDrawables(); ++i )
35     {
36         osg::Drawable* drawable = geode.getDrawable(i);
37         std::cout << spaces() << drawable->libraryName() << "::"
38           << drawable->className() << std::endl;
39     }
40 
41     traverse( geode );
42     _level--;
43 }
44 int main()
45 {
46 osg::ArgumentParser arguments( &argc, argv );
47 osg::ref_ptr<osg::Node> root = osgDB::readNodeFiles( arguments );
48 if ( !root )
49 {
50     OSG_FATAL << arguments.getApplicationName() <<": No data
51       loaded." << std::endl;
52     return -1;
53 }
54 InfoVisitor infoVisitor;
55 root->accept( infoVisitor );
56 osgViewer::Viewer viewer;
57 viewer.setSceneData( root.get() );
58 return viewer.run();
59 }

2.2 设置渲染状态

  osg::StateSet类封装了OpenGL状态机,在裁剪和渲染遍历中通过push和pop管理渲染状态。osg::StateAttribute类记录了渲染状态属性,渲染模式的作用类似于可以打开和关闭的开关,包含指示OpenGL模式类型的枚举参数。osg::StateSet类将属性与模式分为两类:纹理和非纹理。示例为设置节点属性为多边形模式。

1 osg::ref_ptr<osg::PolygonMode> pm = new osg::PolygonMode;
2 pm->setMode(osg::PolygonMode::FRONT_AND_BACK,
3 osg::PolygonMode::LINE);
4 transformation1->getOrCreateStateSet()->setAttribute( pm.get() );

  多边形模式不需要使用setMode()方法。

      节点的状态集将会影响当前节点和子节点。子节点将继承父节点的状态集。osg::StateAttribute::OVERRIDE表示所有子节点状态被覆盖; StateAttribute::PROTECTED表示保持子节点自身状态集不变,优先度高。示例为两个飞机模型节点,改变节点状态时分别用OVERRIDE和PROTECTED标记,结果只有transformation2状态改变。

1 transformation1->getOrCreateStateSet()->setMode( GL_LIGHTING,
2     osg::StateAttribute::OFF );
3 transformation2->getOrCreateStateSet()->setMode( GL_LIGHTING,
4     osg::StateAttribute::OFF|osg::StateAttribute::PROTECTED);
5 root->getOrCreateStateSet()->setMode( GL_LIGHTING,
6     osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE );

  osg中支持的渲染属性和模式:

  示例为创建四边形并加载显示纹理。

 1 #include <osg/Texture2D>
 2 #include <osg/Geometry>
 3 #include <osgDB/ReadFile>
 4 #include <osgViewer/Viewer>
 5 int main()
 6 {
 7 osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
 8 vertices->push_back( osg::Vec3(-0.5f, 0.0f,-0.5f) );
 9 vertices->push_back( osg::Vec3( 0.5f, 0.0f,-0.5f) );
10 vertices->push_back( osg::Vec3( 0.5f, 0.0f, 0.5f) );
11 vertices->push_back( osg::Vec3(-0.5f, 0.0f, 0.5f) );
12 osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array;
13 normals->push_back( osg::Vec3(0.0f,-1.0f, 0.0f) );
14 osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array;
15 texcoords->push_back( osg::Vec2(0.0f, 0.0f) );
16 texcoords->push_back( osg::Vec2(0.0f, 1.0f) );
17 texcoords->push_back( osg::Vec2(1.0f, 1.0f) );
18 texcoords->push_back( osg::Vec2(1.0f, 0.0f) );
19 osg::ref_ptr<osg::Geometry> quad = new osg::Geometry;
20 quad->setVertexArray( vertices.get() );
21 quad->setNormalArray( normals.get() );
22 quad->setNormalBinding( osg::Geometry::BIND_OVERALL );
23 quad->setTexCoordArray( 0, texcoords.get() );
24 quad->addPrimitiveSet( new osg::DrawArrays(GL_QUADS, 0, 4) );
25 
26 osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
27 osg::ref_ptr<osg::Image> image =
28     osgDB::readImageFile( "Images/lz.rgb" );
29 texture->setImage( image.get() );
30 
31 osg::ref_ptr<osg::Geode> root = new osg::Geode;
32 root->addDrawable( quad.get() );
33 root->getOrCreateStateSet()->setTextureAttributeAndModes(
34     0, texture.get() );
35 
36 osg::ref_ptr<osg::Geode> root = new osg::Geode;
37 root->addDrawable( quad.get() );
38 root->getOrCreateStateSet()->setTextureAttributeAndModes(
39     0, texture.get() );
40 osgViewer::Viewer viewer;
41 viewer.setSceneData( root.get() );
42 return viewer.run();
43 }

  osg::setRenderingHint方法设置节点渲染顺序。确保半透明对象在不透明对象之后渲染,

示例为正确显示一个半透明对象。

 1 #include <osg/BlendFunc>
 2 #include <osg/Texture2D>
 3 #include <osg/Geometry>
 4 #include <osgDB/ReadFile>
 5 #include <osgViewer/Viewer>
 6 int main()
 7 {
 8 osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
 9 vertices->push_back( osg::Vec3(-0.5f, 0.0f,-0.5f) );
10 vertices->push_back( osg::Vec3( 0.5f, 0.0f,-0.5f) );
11 vertices->push_back( osg::Vec3( 0.5f, 0.0f, 0.5f) );
12 vertices->push_back( osg::Vec3(-0.5f, 0.0f, 0.5f) );
13 osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array;
14 normals->push_back( osg::Vec3(0.0f,-1.0f, 0.0f) );
15 osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array;
16 texcoords->push_back( osg::Vec2(0.0f, 0.0f) );
17 texcoords->push_back( osg::Vec2(0.0f, 1.0f) );
18 texcoords->push_back( osg::Vec2(1.0f, 1.0f) );
19 texcoords->push_back( osg::Vec2(1.0f, 0.0f) );
20 
21 osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
22 colors->push_back( osg::Vec4(1.0f, 1.0f, 1.0f, 0.5f) );
23 
24 osg::ref_ptr<osg::Geometry> quad = new osg::Geometry;
25 quad->setVertexArray( vertices.get() );
26 quad->setNormalArray( normals.get() );
27 quad->setNormalBinding( osg::Geometry::BIND_OVERALL );
28 quad->setColorArray( colors.get() );
29 quad->setColorBinding( osg::Geometry::BIND_OVERALL );
30 quad->setTexCoordArray( 0, texcoords.get() );
31 quad->addPrimitiveSet( new osg::DrawArrays(GL_QUADS, 0, 4) );
32 osg::ref_ptr<osg::Geode> geode = new osg::Geode;
33 geode->addDrawable( quad.get() );
34 
35 osg::ref_ptr<osg::Geometry> quad = new osg::Geometry;
36 quad->setVertexArray( vertices.get() );
37 quad->setNormalArray( normals.get() );
38 quad->setNormalBinding( osg::Geometry::BIND_OVERALL );
39 quad->setColorArray( colors.get() );
40 quad->setColorBinding( osg::Geometry::BIND_OVERALL );
41 quad->setTexCoordArray( 0, texcoords.get() );
42 quad->addPrimitiveSet( new osg::DrawArrays(GL_QUADS, 0, 4) );
43 osg::ref_ptr<osg::Geode> geode = new osg::Geode;
44 geode->addDrawable( quad.get() );
45 
46 osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
47 osg::ref_ptr<osg::Image> image =
48     osgDB::readImageFile( "Images/lz.rgb" );
49 texture->setImage( image.get() );
50 
51 osg::ref_ptr<osg::BlendFunc> blendFunc = new osg::BlendFunc;
52 blendFunc->setFunction( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
53 
54 osg::StateSet* stateset = geode->getOrCreateStateSet();
55 stateset->setTextureAttributeAndModes( 0, texture.get() );
56 stateset->setAttributeAndModes( blendFunc );
57 stateset->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
58 
59 osg::ref_ptr<osg::Group> root = new osg::Group;
60 root->addChild( geode.get() );
61 root->addChild( osgDB::readNodeFile("glider.osg") );
62 osgViewer::Viewer viewer;
63 viewer.setSceneData( root.get() );
64 return viewer.run();
65 
66 }