3.2 基本几何体的绘制
本节的例子主要是基本图形的绘制,如线段、三角形、圆及四边形等。
我们知道任何复杂的东西都是由一些简单的部分组合构成的,对于OSG创建的场景和对象也同样如此,它们是有简单的图元(我们把构成3D对象的构件成为图元)按照一定的方式排列和组合而成的,OSG中的所有图元都是一维或二维对象,包括单个的点、直线和复杂的多边形。
3.2.1 几何体类
osg::Geometry继承自osg::Drawable。它的主要作用是对指定绘制几何体的顶点数及对数据的解析,主要提供了如下3大类方法:
(1)指定向量数据。如顶点数据、纹理坐标及颜色等一系列向量数据,可以通过下面的几个函数来实现。
函数 说明 void setVertexArray(Array* array) 设置顶点数组 void setVertexData(const ArrayData& arrayData) 设置顶点数组数据 void setVertexIndices(IndexArray* array) 设置顶点索引数组 void setNormalArray(Array* array) 设置法线数组 void setNormalData(const ArrayData& arrayData) 设置法线数组数据 void setNormalIndices(IndexArray* array) 设置法线索引数组 void setColorArray(Array* array) 设置颜色数组数据 void setColorData(const ArrayData& arrayData) 设置颜色数组数据 void setColorIndices(IndexArray* array) 设置颜色索引数组 void setTexCoordArray(unsigned int unit,Array*) 设置纹理坐标数据 void setTexCoordData(unsigned int index,const ArrayData& arrayData) 设置纹理坐标数据 void setTexCoordIndices(unsigned int unit,IndexArray*) 设置纹理坐标数据
(2)设置绑定方式。数据绑定主要有两项,即法线和颜色,可以通过下面的两个函数来实现。
函数 说明 void setNormalBinding(AttributeBinding ab) 设置法线绑定方式 void setColorBinding(AttributeBinding ab) 设置颜色绑定方式
绑定方式主要有下面几种:
宏名称 说明 BIND_OFF 不启用绑定 BIND_OVERALL 绑定全部的顶线 BIND_PER_PRIMITIVE_SET 单个绘图基元绑定 BIND_PER_PERMITIVE 单个独立的绘图基元绑定 BIND_PER_VERTEX 单个顶点绑定
(3)数据解析。当指定了各种向量数据和绑定方式之后,采用何种方式来渲染几何体就是最为关键的。不同的方式下,渲染出来的图形是不一样的,即使效果一样,可能面数或内部机制等也是有区别的。数据解析主要通过如下函数来指定:
bool addPrimitiveSet(PrimitiveSet* primitiveSet);
// osg::PrimitiveSet是无法初始化的虚基类,因此这里主要是调用它的子类来指定数据渲染,最常用的就是前面介绍的osg::DrawArrays,用法比较简单,初始化一个对象实例,参数说明见前面osg::DrawArray类
通过前面的讲述可知,绘制并渲染几何体主要有如下3大步骤:
(1)创建各种向量数据,如顶点、纹理坐标、颜色和法线等。需要注意的是,添加顶点数据时主要按照逆时针顺序添加,以确保背面剔除(backface culling)的正确。
(2)实例化一个几何体对象(osg::Geometry),设置顶点坐标数组、纹理坐标数组、颜色数组、法线数组、绑定方式及数据解析。
(3)加入叶节点绘制并渲染。
3.2.2 基本几何体绘制示例
基本几何体绘制(osg::Geometry)示例演示了创建一个几何体的过程,示例中创建了最简单的四边形。通过该示例学会如何创建简单的几何体。
#include<osgViewer/Viewer>
#include<osg/Node>
#include<osg/Group>
#include<osg/Geode>
#include<osgDB/ReadFile>
#include<osgDB/WriteFile>
#include<osgUtil/Optimizer>
// 创建一个四边形节点
osg::ref_ptr<osg::Node>createQuad()
{
// 创建一个叶节点对象
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
// 创建一个几何体对象
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry();
// 创建顶点数组,注意顶点数组的添加顺序是逆时针
osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array();
// 添加数据
v->push_back(osg::Vec3(0.0f,0.0f,0.0f));
v->push_back(osg::Vec3(1.0f,0.0f,0.0f));
v->push_back(osg::Vec3(1.0f,0.0f,1.0f));
v->push_back(osg::Vec3(0.0f,0.0f,1.0f));
// 设置顶点数据
geom->setVertexArray(v.get());
// 创建纹理坐标
osg::ref_ptr<osg::Vec2Array> vt = new osg::Vec2Array();
vt->push_back(osg::Vec2(0.0f,0.0f));
vt->push_back(osg::Vec2(1.0f,0.0f));
vt->push_back(osg::Vec2(1.0f,1.0f));
vt->push_back(osg::Vec2(0.0f,1.0f));
// 设置纹理坐标
geom->setTexCoordArray(vt);
// 创建颜色数组
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));
// 设置颜色数组
geom->setColorArray(vc.get());
// 设置颜色的绑定方式为单个顶点
geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
// 创建法线数组
osg::ref_ptr<osg::Vec3Array> nc = new osg::Vec3Array();
nc->push_back(osg::Vec3(0.0f,-1.0f,0.0f));
// 设置法线数组
geom->setNormalArray(nc.get());
// 设置法线的绑定方式为全部顶点
geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
// 添加图元,绘制基元为四边形
geom->addPrimitiveSet(new osg::DrawArray(osg::PrimitiveSet::QUADS,0,4));
// 添加到叶节点
geode->addDrawable(geom.get());
return geode.get();
}
//----------------------------------------------------------------------------
int main()
{
// 创建Viewer对象,场景浏览器
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
osg::ref_ptr<osg::Group> root = new osg::Group();
// 添加到场景
root->addChild(CreateQuad());
// 优化场景数据
osgUtil::Optimizer optimizer;
optimizer.optimize(root.get());
viewer->setSceneData(root.get());
viewer->realize();
viewer->run();
return 0;
}
3.2.3 索引绑定几何体绘制示例
#include<osgViewer/Viewer>
#include<osg/Node>
#include<osg/Geode>
#include<osg/Group>
#include<osgDB/ReadFile>
#include<osgDB/WriteFile>
#include<osgUtil/Optimizer>
// 创建一个四边形节点
osg::ref_ptr<osg::Node> createQuad()
{
// 创建一个叶节点对象
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
// 创建一个几何体对象
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry();
// 创建顶点数组
osg::ref_ptr<osg::Vec3Array> v = new osg:: vec3Array();
// 添加数据
v->push_back(osg::Vex3(0.0f,0.0f,0.0f));
v->push_back(osg::Vex3(1.0f,0.0f,0.0f));
v->push_back(osg::Vex3(1.0f,0.0f,1.0f));
v->push_back(osg::Vex3(0.0f,0.0f,1.0f));
v->push_back(osg::Vex3(0.0f,-1.0f,0.0f));
// 设置顶点数据
geom->setVertexArray(v.get());
// 创建四边形顶点索引数组,指定绘图基元为四边形,注意添加顺序
osg::ref_ptr<osg::DrawElementsUInt>quad = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS,0);
// 添加数据
quad->push_back(0);
quad->push_back(1);
quad->push_back(2);
quad->push_back(3);
// 添加到几何体
geom->addPrimitiveSet(quad.get());
// 创建三角形顶点索引数组,指定绘图基元为三角形,注意添加顺序
osg::ref_ptr<osg::DrawElementUInt> triangle = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES,0);
triangle->push_back(4);
triangle->push_back(0);
triangle->push_back(3);
// 添加到几何体
geom->addPrimitiveSet(triangle.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));
// 创建颜色索引数组
osg::TemplateIndexArray<unsigned int ,osg::Array::UIntArrayType,4,4>* colorIndex = new osg::TemplateIndexArray<unsigned int ,osg::Array::UIntArrayType,4,4>();
// 添加数据,注意添加数组顺序与顶点一一对应
colorIndex->push_back(0);
colorIndex->push_back(1);
colorIndex->push_back(2);
colorIndex->push_back(3);
colorIndex->push_back(2);
// 设置颜色数组
geom->setColorArray(vc.get());
// 设置颜色索引数组
geom->setColorIndices(colorIndex);
// 设置颜色的绑定方式为单个顶点
geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
// 创建法线数组
osg::ref_ptr<osg::Vec3Array> nc = new osg::Vec3Array();
nc->push_back(osg::Vec3(0.0f,-1.0f,0.0f));
// 设置法线数组
geom->setNormalArray(nc.get());
// 设置返现的绑定方式为全部顶点
geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
// 添加到叶子节点
geode->addDrawable(geom.get());
return geode.get();
}
//--------------------------------------------------------------------------------------
int main()
{
// 创建Viewer对象场景浏览器
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
osg::ref_ptr<osg::Group> root = new osg::Group();
root.addChild(createQuad());
osgUtil::Optimizer optimizer;
optimizer.optimize(root.get());
viewer->setSceneData(root.get());
viewer->realize();
viewer->run();
return 0;
}