在 OSG 当中所有的加入到场景的数据都会加入到一个 Group 当中,而几何图元做为一种需要绘制的对象而非模型也有一个类专门组织, 这个类就是osg::Geode, 该类的作用就是组织一些绘制的对象, 然后传给Group。如图 4.1 所示。
从图上可以看出所有基本的绘制功能完成后都会把结点汇集在一个 osg::Geode 当中,然后该 osg::Geode 再自己加入到 root 中完成所有子结点的绘制。
现在首先来看一些 OSG 中的最基本的绘制路数。下面我们要绘制一个正方形,绘制有色彩,未贴图。首先我们必须要申请一个 osg::Geometry,把这个 Geometry 加入到 Geode 就可以了。 在这个 Geometry 中要设置一些元素,最基本的是顶点 Vertex,颜色 color,以及顶点的关联方式和法线 normal.就可以了。如图 4.2 所示。
#ifdef _DEBUG
#pragma comment(lib,"osgd.lib")
#pragma comment(lib,"osgDBd.lib")
#pragma comment(lib,"osgViewerd.lib")
#pragma comment(lib,"OpenThreadsd.lib")
#pragma comment(lib,"osgGAd.lib")
#else
#pragma comment(lib,"osg.lib")
#pragma comment(lib,"osgDB.lib")
#pragma comment(lib,"osgViewer.lib")
#pragma comment(lib,"OpenThreads.lib")
#pragma comment(lib,"osgGA.lib")
#endif
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osg/Node>
#include <osg/Geode>
#include <osg/Geometry>
//函数声明,绘制该正方体的代码都在这一个函数当中,返回的是 osg::Node 类型。
osg::ref_ptr<osg::Node> createQuad() ;
void main()
{
osgViewer::Viewer viewer;
osg::Group * root = new osg::Group() ;
root ->addChild(createQuad().get()) ;
viewer.setSceneData(root);
viewer.realize();
viewer.run();
}
osg::ref_ptr<osg::Node> createQuad()
{
//申请了一个几何体结点
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
//首先定义四个点
osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
geom->setVertexArray( v.get() );
v->push_back( osg::Vec3( -1.f, 0.f, -1.f ) );
v->push_back( osg::Vec3( 1.f, 0.f, -1.f ) );
v->push_back( osg::Vec3( 1.f, 0.f, 1.f ) );
v->push_back( osg::Vec3( -1.f, 0.f, 1.f ) );
//定义颜色数组
osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array;
geom->setColorArray( c.get() );
geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
c->push_back( osg::Vec4( 1.f, 0.f, 0.f, 1.f ) );
c->push_back( osg::Vec4( 0.f, 1.f, 0.f, 1.f ) );
c->push_back( osg::Vec4( 0.f, 0.f, 1.f, 1.f ) );
c->push_back( osg::Vec4( 1.f, 1.f, 1.f, 1.f ) );
//定义法线
osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;
geom->setNormalArray( n.get() );
geom->setNormalBinding( osg::Geometry::BIND_OVERALL );
n->push_back( osg::Vec3( 0.f, -1.f, 0.f ) );
//设置顶点关联方式
geom->addPrimitiveSet(
new osg::DrawArrays( osg::PrimitiveSet::QUADS, 0, 4 ) );
//几何组结点
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
geode->addDrawable( geom.get() );
return geode.get();
}
下面例举所有可绘制的几何图元:POINTS[点],LINES[线],LINE_STRIP[线带],LINE_LOOP[闭合线段],TRIANGLES[三角形],TRIANGLE_STRIP[三角带],TRIANGLE_FAN[三角扇],QUADS[四方块],QUAD_STRIP[四方块带],POLYGON[多边形],在这里我们要以封闭的直线为例来说明如何设置线宽属性。
在 OSG 中设置直线线宽的专门有一个函数来管理,叫做 LineWidth,它本身属于状态与属性类别中的类。事实上也是从那里派生而来。所有设置状态的操作都与此类似。
#ifdef _DEBUG
#pragma comment(lib,"osgd.lib")
#pragma comment(lib,"osgDBd.lib")
#pragma comment(lib,"osgViewerd.lib")
#pragma comment(lib,"OpenThreadsd.lib")
#pragma comment(lib,"osgGAd.lib")
#else
#pragma comment(lib,"osg.lib")
#pragma comment(lib,"osgDB.lib")
#pragma comment(lib,"osgViewer.lib")
#pragma comment(lib,"OpenThreads.lib")
#pragma comment(lib,"osgGA.lib")
#endif
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osg/Node>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/LineWidth>
//函数声明,绘制该正方体的代码都在这一个函数当中,返回的是 osg::Node 类型。
osg::ref_ptr<osg::Node> createQuad() ;
void main()
{
osgViewer::Viewer viewer;
osg::Group * root = new osg::Group() ;
root ->addChild(createQuad().get()) ;
viewer.setSceneData(root);
viewer.realize();
viewer.run();
}
osg::ref_ptr<osg::Node> createQuad()
{
//申请了一个几何体结点
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
osg::ref_ptr <osg::LineWidth> LineSize = new osg::LineWidth;
LineSize ->setWidth (10.0) ;
geom->getOrCreateStateSet()->setAttributeAndModes(LineSize.get (),osg::StateAttribute::ON);
//首先定义四个点
osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
geom->setVertexArray( v.get() );
v->push_back( osg::Vec3( -1.f, 0.f, -1.f ) );
v->push_back( osg::Vec3( 1.f, 0.f, -1.f ) );
v->push_back( osg::Vec3( 1.f, 0.f, 1.f ) );
v->push_back( osg::Vec3( -1.f, 0.f, 1.f ) );
//定义颜色数组
osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array;
geom->setColorArray( c.get() );
geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
c->push_back( osg::Vec4( 1.f, 0.f, 0.f, 1.f ) );
c->push_back( osg::Vec4( 0.f, 1.f, 0.f, 1.f ) );
c->push_back( osg::Vec4( 0.f, 0.f, 1.f, 1.f ) );
c->push_back( osg::Vec4( 1.f, 1.f, 1.f, 1.f ) );
//定义法线
osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;
geom->setNormalArray( n.get() );
geom->setNormalBinding( osg::Geometry::BIND_OVERALL );
n->push_back( osg::Vec3( 0.f, -1.f, 0.f ) );
//设置顶点关联方式
geom->addPrimitiveSet(
new osg::DrawArrays( osg::PrimitiveSet::LINE_LOOP, 0, 4 ) );
//几何组结点
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
geode->addDrawable( geom.get() );
return geode.get();
}
如同 OpenGL 一样,OSG 同样有一套内置几何类型,这些几何类型都在类 osg::Shape 中,这些 shape 本身都可以本当成一个 Draw 结点加入到 geode 中,然后再人 geode 中添加到 root 里进行渲染。
形状共有九种,分别为:osg::Box[盒子],osg::Capsule[胶囊形],osg::CompositeShape[组合型],osg::Cone[圆锥形],osg::Cylinder[圆柱形],osg::HeightField[高程形],osg::InfinitePlane[有限面],osg::Sphere[球形],osg::TriangleMesh[三角蒙皮]。
下面来看一下这些内置几何类型的渲染过程,如图 4.5 所示。
#ifdef _DEBUG
#pragma comment(lib,"osgd.lib")
#pragma comment(lib,"osgDBd.lib")
#pragma comment(lib,"osgViewerd.lib")
#pragma comment(lib,"OpenThreadsd.lib")
#pragma comment(lib,"osgGAd.lib")
#else
#pragma comment(lib,"osg.lib")
#pragma comment(lib,"osgDB.lib")
#pragma comment(lib,"osgViewer.lib")
#pragma comment(lib,"OpenThreads.lib")
#pragma comment(lib,"osgGA.lib")
#endif
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osg/Node>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/ShapeDrawable>
#include <osg/Shape>
osg::ref_ptr<osg::Node> createShape() ;
void main()
{
osgViewer::Viewer viewer;
osg::Group * root = new osg::Group() ;
root ->addChild(createShape().get()) ;
viewer.setSceneData(root);
viewer.realize();
viewer.run();
}
osg::ref_ptr<osg::Node> createShape()
{
//几何组结点
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
float radius = 0.08f;
float height = 0.1f;
osg::TessellationHints* hints = new osg::TessellationHints;
hints->setDetailRatio(0.5f);
geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f,0.0f,0.0f),radius),hints));
geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.2f,0.0f,0.0f),2*radius),hints));
geode->addDrawable(new osg::ShapeDrawable(new osg::Cone(osg::Vec3(0.4f,0.0f,0.0f),radius,height),hints));
geode->addDrawable(new osg::ShapeDrawable(new osg::Cylinder(osg::Vec3(0.60f,0.0f,0.0f),radius,height),hints));
geode->addDrawable(new osg::ShapeDrawable(new osg::Capsule(osg::Vec3(0.80f,0.0f,0.0f),radius,height),hints));
return geode.get();
}
参考书:FreeSouth的《QpenSceneGraph程序设计》