开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 29 天
1 场景基本绘图类
在OSG 中创建几何体的方法比较简单,通常有3种处理几何体的手段,一是使用松散封装的OpenGL 绘图基元;二是使用OSG中的基本几何体;三是从文件中导入场景模型。
使用松散封装的OpenGL绘图基元绘制几何体具有很强的灵活性,但工作量通常非常大,当面对大型场景时,绘制几何体将是一项非常艰巨而富有挑战的工作,因此,通常还是采用读入外部模型的方法。读取外部模型的方法在后面会有专门的介绍。
2 向量与数组类
在OSG中定义了大量的类来保存数据,数据通常是以向量的形式来表示的,向量数据主要包括顶点坐标、纹理坐标、颜色和法线等。
例如,定义osg::Vec2来保存纹理坐标;定义osg::Vec3来保存顶点坐标和法线坐标;定义osg::Vec4保存颜色的RGBA值。osg::Vec2、osg::Vec3和osg::Vec4是分别用来保存向量的二维数组、三维数组和四维数组,这些类不仅能够保存各种数据,还提供了向量的基本运算机制,如加、减、乘、除四则元算、点积和单位化等相关的操作。
在OSG中还定义了模板数组用来保存对象,例如,可以用顶点索引对象(osg::DrawElementsUInt)来保存顶点索引,用颜色索引(osg::TemplateIndexeArray)来保存颜色。
但最常用的还是保存向量数据,如 osg::Vec3Array 来保存众多顶点坐标、osg::Vec2Array 保存纹理坐标等,这些模板数组都继承自 std::Vector,因此,它们具有向量的基本操作方法,例如,可以利用 push_back()添加一个元素,可以利用pop_back()删除一个元素,同样也可以使用clear()删除所有的元素。
3 Drawable类
Drawable类是一个纯基类,无法实例化。作为可绘制对象基类的osg::Drawable类,它派生了很多类,它的继承关系图如下图所示。
从上图可以看出,由osg::Drawable派生的类有9个,分别是osg::rawPixels、osg::Geometry、 osg::ShapeDrawable、osgParticle::articleSystem、osgParticle::PrecipitationEffect::PrecipitationDrawable、 osgShadow::OccluderGeometry、osgShadow::Shadow::VolumeGeometry、osgSim::ImpostorSprite 和 osgText::TextBase。
其中,从OSG核心库派生出了3个类,分别是osg::DrawPiexels类(主要封装了OpenGL 中gIDrawPixels(的功能)、osg::Geometry类(绘制几何体的类,应用比较灵活)和osg::ShapeDrawable 类(主要封装了一些已经定义好的几何体,不需要设置坐标即可直接调用,如长方体、正方体、球体等)。
其他的类中,有两个派生自粒子系统库,有两个派生自阴影库,还有两个分别派生自osgSim库和osgText文字库,在后面的章节中都会对这些进行介绍。
3 PrimitiveSet 类
osg::PrimitiveSet类继承自osg::Object虚基类,但它不具备一般场景中的特性。osg::PrimitiveSet类 的继承关系图如下图所示。
该类主要松散封装了 OpenGL的绘图基元,通过指定绘图基元来指定几何体顶点将采用哪一种或几种基元绘制。常用的绘图基元包括如下几种:
POINTS=GL_POINTS //绘制点
LINES=GL_LINES //绘制线
LINE_STRIP-GL_LINE_STRIP //绘制多段线
LINE_LOOP-GL_LINE_LOOP //绘制封闭线
TRIANGLES-GL_TRIANGLES //绘制一系列的三角形(不共用顶点)
TRIANGLE_STRIP=GL_TRIANGLE_STRIP //绘制一系列三角形(共用后面的两个顶点)
TRIANGLE_FAN=GL_TRIANGLE_FAN //绘制一系列三角形,顶点顺序与上一条语句绘制的三角形不同
QUADS=GL_QUADS //绘制四边形
QUAD_STRIP=GL_QUAD_STRIP //绘制一系列四边形
POLYGON=GL_POLYGON //绘制多边形
从osg::PrimitiveSet类的继承关系图可以看出,它的派生类主要有如下3个:
- osg::DrawArrays类。继承自 osg::PrimitiveSet,它封装了glDrawArrays()顶点数组绘图命令, 用于指定顶点和绘图基元。
- osg::DrawElements 类。它又派生出3个子类,分别是osg::DrawElementsUJByte、osg::DrawElementsUShort和osg::DrawElementsUInt,封装了gIDrawElements()的指令,可以起索引的作用,在后面的示例中会用到。
- osg::DrawArrayLengths类。它的主要作用是多次绘制,即多次调用gIDrawArrays(),且每次均 使用不同的长度和索引范围,在绘制过程中用得不是很多。
DrawArrays的基本用法如下:
osg:DrawArrays:DrawArrays(GLenum mode,GLint first,GLsizei count);
// 参数说明:
// 第一个参数是指定的绘图基元,即前面所列举的常见绘图基元;
// 第二个参数是指绘制几何体的第一个顶点数在指定顶点的位置数;
// 第三个参数是使用的顶点的总数
还有一点值得注意的是,虽然osg::PrimitiveSet类提供与OpenGL一样的顶点机制,但是在内部渲染上还是有一定区别的。根据渲染环境的不同,渲染的方式也是不一样的,可能会采用顶点、顶点数组、显示列表或者glBegin()/glEnd()来渲染几何体,继承自Drawable 类的对象(如Geometry)在默认 条件下将使用显示列表。其中,osg::Drawable::setUseDisplayList(false)用于手动禁止使用显示列表。
还有一种比较特殊的情况,如果设置BIND_PER_PRIMITIVE绑定方式,那么OSG将采用glBegin(/glEnd())函数进行渲染。因为在设置使用绑定方式为BIND_PER_PRIMITIVE后,它就为每个独立的几何图元设置一种绑定属性。