在osg中,场景图形采用一种自顶向下的,分层的树状数据结构来组织空间数据集,以提高渲染的效率
场景图形树结构的顶部是一个根节点,从根节点向下延伸,各个组节点中均包含了几何信息和用于控制其外观的渲染状态信息。根节点和各个组节点都可以有零个(实际上是没有执行任何操作)或多个子成员。在场景图形的最底部,各个叶节点包含了构成场景中物体的实际几何信息。
首先,必须明确的是,在应用程序中所有几何体的渲染都必须与Geode节点相关联。在osg::Geode类中,也提供了addDrawable()函数来关联应用程序中需要渲染的几何体信息。一个Geode可以包含多个Drawable,Geode维护了一个Drawable的列表。因此在OSG中我们想要绘制诸如三角形等.最终需要使用的肯定还是Geode叶子节点.然后将Drawable通过addDrawable()方法加入Geode下...实际上要生成几何体adddrawable()的要么是一个Geomety,要么是一个shapedrawable。
在osg中,通常有三种生成几何体的手段:一是松散封装的OpenGL绘图基元osg::Geometry,二是使用OSG中预定义的基本几何体;三是从文件中导入场景模型。
不管是松散封装的OpenGL的绘图基元,还是osg自己预定义的几何体,其基类都是osg::Drawable,它派生自osg::Object(该类派生自osg::referenced),具体继承关系如下图所示,
注意:最常用的是DrawPixels,Geometry,shapedrawable,osgText::TextBase
其中:DrawPixels用于绘制图像,具体用法如下:
osg::DrawPixels* pixels = new osg::DrawPixels();
pixels->setPosition(osg::Vec3((float)vX[0],(float)vY[1] ,(float)vZ[1]));
QString imagePath = ::GetImagePath() + pWell->GetWellSymbol();
pixels->setImage(osgDB::readImageFile(imagePath.toStdString()));
//声明一个图片节点
osg::Geode* imagNode = new osg::Geode();
imagNode->addDrawable(pixels);
osgText用于绘制文字,具体用法如下:
QString strFont1 = ::GetImagePath() + "fonts/MicroSoftYahei.ttf";
QTextCodec *code = QTextCodec::codecForName("gb18030");
std::string strFont2 = strFont1.toStdString();
if( code )
{
strFont2 = code->fromUnicode(strFont1).data();
}
{
m_pText = new osgText::Text;
m_pText->setDataVariance(osg::Object::DYNAMIC);
//p->setUseDisplayList(false);
m_pText->setFont(strFont2 );
m_pText->setDrawMode(osgText::Text::TEXT);
m_pText->setFontResolution(15,15);
m_pText->setCharacterSize(15);
m_pText->setAlignment(osgText::Text::CENTER_CENTER );
m_pText.setAxisAlignment(osgText::Text::SCREEN);//让文字所在平面始终对着屏幕
m_pText->setColor(osg::Vec4f(0,0,0,1) );
}
m_pGeode = new osg::Geode();
m_pGeode->clone( osg::CopyOp::DEEP_COPY_ALL );
m_pGeode->addDrawable( m_pText );
m_pSwitch = new osg::Switch;
m_pSwitch->addChild( m_pGeode );
下面重点讲解Geometry和ShapeDrawable。
在实际应用中,往场景里面添加一个几何体,都必须先定义个geode,osg::Geode* geode = new osg::Geode;
然后要么用自定义几何体osg::Shape,使用方式:geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(osg::vec3(0.0f,0.0f,0.0f),radius),hints.get()));
osg中提供了大量的预定义几何体,来简化场景的绘制,继承关系如图所示。如果要渲染这些几何体,必须将其挂到某个geode下面,但是geode只能通过adddrawable添加osg::drawable类型,因此实际应用中提供了osg::ShapeDrawable来完成这个功能。在该类的构造函数中提供了关联osg::Shape的方法:
ShapeDrawable(Shape * shape,TessellationHints * hints=0)//第一个参数即为要绘制的几何体,第二个为网格化类,主要用于设置几何体的精细程度
要么用Geometry,使用方式:
osg::ref_ptr<osg::Geode> geode1 = new osg::Geode();
osg::ref_ptr<osg::Geometry> geom1 = new osg::Geometry();
//创建顶点数组
osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array();
v->push_back(osg::Vec3(458000,0,-1500));
v->push_back(osg::Vec3(458000,0,-2750));
v->push_back(osg::Vec3(452000,0,-2750));
v->push_back(osg::Vec3(452000,0,-1500));
geom1->setVertexArray(v.get());
//设置颜色数组
osg::ref_ptr<osg::Vec4Array> vc = new osg::Vec4Array();
vc->push_back(osg::Vec4(1.0f,0.0f,0.0f,1.0f));
vc->push_back(osg::Vec4(0.0f,1.0f,0.0f,1.0f));
vc->push_back(osg::Vec4(0.0f,0.0f,1.0f,1.0f));
vc->push_back(osg::Vec4(1.0f,1.0f,0.0f,1.0f));
geom1->setColorArray(vc.get());
geom1->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
//设置法线数组
osg::ref_ptr<osg::Vec3Array> nc = new osg::Vec3Array();
nc->push_back(osg::Vec3(0,1,0));
geom1->setNormalArray(nc.get());
geom1->setNormalBinding(osg::Geometry::BIND_OVERALL);
//添加图元,绘图基元为四边形
geom1->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
geode1->addDrawable(geom1.get());
m_pRootSwitch->addChild(geode1);
上一段程序中还设置了颜色数据,法线数据与顶点数据绑定的方式,即setColorBinding和setNormalBinding,绑定数据的方式有以下几种:
BIND_OFF | 取消绑定 | 此时,颜色数据或者法线数据与顶点数据完全没有关系,顶点数据的颜色和法线方向完全由缺省值决定。 |
BIND_OVERALL | 绑定全部几何体 | 此时,颜色数组或者法线坐标数组中只需要保存一个数据,该数据将影响此Geometry类的所有顶点坐标。例如,将红色绑定到全部几何体上,则这个类绘制出的所有物体均是红色的。 |
BIND_PER_PRIMITIVE | 绑定逐个几何体 | 此时,颜色数组或者法线坐标数组中保存的数据数量应当与用户将要绘制的几何体数量相同。例如,用户依据8个顶点来绘制两个四边形时,可以分别为它们设置两个法线坐标,并使用此参数进行绑定。 |
BIND_PER_VERTEX | 绑定逐个点 | 逐点绑定。比如上面的例子,将四个颜色数据分别绑定到四个顶点坐标,可以实现顶点颜色之间的过渡效果。 |
osg::PrimitiveSet类,该类主要松散封装了OpenGL的绘图基元,通过指定绘图基元来指定几何体顶点将采用哪一种或几种基元绘制。继承关系如下图所示,
PrimitiveSet:提供了opengl顶点数组绘图命令的高层次支持。用户可以从Geometry中获得保存的数据,再使用这个类制定要绘制的几何体数据的类型。
在给geometry设置完顶点、颜色、法线、纹理以后,必须通过
geom1->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
来指定要利用这些数据生成一个怎么样的形状。
该行代码中,使用DrawArrays类向Geometry类送入了新几何体的信息,即,该几何体是一个QUADS,它的顶点坐标从索引数组中读入,从第1个索引值开始,共读入4个索引值,组成一个四边形图形。
几何体的形状参数除了QUADS之外,还有数种方式,以用于不同的用户需求,列表如下:
POINTS | 绘制点 | 绘制用户指定的所有顶点。 |
LINES | 绘制直线 | 直线的起点、终点由数组中先后相邻的两个点决定;用户提供的点不止两个时,将尝试继续绘制新的直线。 |
LINE_STRIP | 绘制多段直线 | 多段直线的第一段由数组中的前两个点决定;其余段的起点位置为上一段的终点坐标,而终点位置由数组中随后的点决定。 |
LINE_LOOP | 绘制封闭直线 | 绘图方式与多段直线相同,但是最后将自动封闭该直线。 |
TRIANGLES | 绘制三角形 | 三角形的三个顶点由数组中相邻的三个点决定,并按照逆时针的顺序进行绘制;用户提供的点不止三个时,将尝试继续绘制新的三角形。 |
TRIANGLE_STRIP | 绘制多段三角形 | 第一段三角形的由数组中的前三个点决定;其余段三角形的绘制,起始边由上一段三角形的后两个点决定,第三点由数组中随后的一点决定。 |
TRIANGLE_FAN | 绘制三角扇面 | 第一段三角形的由数组中的前三个点决定;其余段三角形的绘制,起始边由整个数组的第一点和上一段三角形的最后一个点决定,第三点由数组中随后的一点决定。 |
QUADS | 绘制四边形 | 四边形的四个顶点由数组中相邻的四个点决定,并按照逆时针的顺序进行绘制;用户提供的点不止四个时,将尝试继续绘制新的四边形。 |
QUAD_STRIP | 绘制多段四边形 | 第一段四边形的起始边由数组中的前两个点决定,边的矢量方向由这两点的延伸方向决定;起始边的对边由其后的两个点决定,如果起始边和对边的矢量方向不同,那么四边形将会扭曲;其余段四边形的绘制,起始边由上一段决定,其对边由随后的两点及其延伸方向决定。 |
POLYGON | 绘制任意多边形 | 根据用户提供的顶点的数量,绘制多边形。 |
和opengl对比:
osg::PrimitiveSet::POINTS对应OpenGL中的GL_POINTS绘制单独的点
osg::PrimitiveSet::LINES对应OpenGL中的GL_LINES绘制每两点连接的线
osg::PrimitiveSet::LINE_STRIP对应OpenGL中的GL_LINE_STRIP绘制依次连接各点的线
osg::PrimitiveSet::LINE_LOOP对应OpenGL中的GL_LINE_LOOP绘制依次连接各点的线,首尾相连
osg::PrimitiveSet::POLYGON对应OpenGL中的GL_POLYGON绘制依次连接各点的多边形
osg::PrimitiveSet::QUADS对应OpenGL中的GL_QUADS绘制依次连接每四点的四边形
如:1、2、3、4、5、6、7、8点 绘制结果1、2、3、4组成四边形,5、6、7、8组成四边形
osg::PrimitiveSet::QUAD_STRIP对应OpenGL中的GL_QUAD_STRIP绘制四边形
如:1、2、3、4、5、6、7、8点 绘制结果1、2、3、4组成四边形,3、4、5、6组成四边形、5、
6、7、8组成四边形
osg::PrimitiveSet::TRIANGLES对应OpenGL中的GL_TRIANGLES绘制每三点连接的三角形
如:1、2、3、4、5、6点 绘制结果1、2、3组成三角形,4、5、6组成三角形
osg::PrimitiveSet::TRIANGLE_STRIP对应OpenGL中的GL_TRIANGLE_STRIP
如:1、2、3、4、5、6点 绘制结果1、2、3组成三角形,2、3、4组成三角形,3、4、5组成三角
形4、5、6组成三角形
osg::PrimitiveSet::TRIANGLE_FAN对应OpenGL中的GL_TRIANGLE_FAN
如:1、2、3、4、5、6点 绘制结果1、2、3组成三角形,1、3、4组成三角形,1、4、5组成三角
形,1、5、6组成三角形