OSG 使用整理(2):设置渲染状态
二、场景管理
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 }