主要参考资料: 《OpenSceneGraph三维渲染引擎编程指南》肖鹏 刘更代 徐明亮 清华大学出版社
前言
使用Osg内部封装的Delaunay三角网绘制图像时,有时会发现会生成很多,意料之外的狭长三角形,在我学习的过程中发现Osg本身的约束类 osgUtil::DelaunayTriangulator,只能对于生成图像形成一个区域的清除,如果可以通过此约束类达成对生成的三角形进行约束,也请留言相互学习。
提示:以下是本篇文章正文内容,下面案例可供参考
一、如何生成三角网
生成三角网的方式,参考于:OpenSceneGraph三维渲染引擎编程指南 一书中Delaunay三角网绘制示例,核心代码如下:
//创建三角网对象 并使用顶点数据初始化
osg::ref_ptr<osgUtil::DelaunayTriangulator> dt = new osgUtil::DelaunayTriangulator(v.get());
//生成三角网
dt->triangulate();
//加入绘图基元
geometry->addPrimitiveSet(dt->getTriangles());
二、实现
1.约束
在参考osgUtil::DelaunayTriangulator 文档是可以发现没有直接显示有函数可以去限制生成三角形,后来发现经过大佬提醒发现 getTriangles()函数,获取三角形,猜想可以通过这个函数实现想要的约束。三角形的约束通过getTriangles()的返回值osg::DrawElementsUInt 来进行实现,此类中并没有成员函数可以限制三角形,但是它继承于一个容器类,所以通过迭代器访问其中元素后,发现其中元素为int,经杨石兴杨老师的指点猜测可能为形成三角形顶点的索引,所以最难点解决。
2.整体代码
代码如下(示例):
//三角网绘制及其约束
osg::ref_ptr<osg::Node> createPointAndOther()
{
//从文件获取数据
std::string dataFile = "../D18.txt";
osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;//点数组
osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array;
int countTwo = 0;
FILE* pfData = fopen(dataFile.c_str(), "r");
if (pfData == NULL)
{
std::cout << "错误" << std::endl;
return NULL;
}
else
{
while (!feof(pfData))
{
float fx(0), fy(0), fz(0);
fscanf(pfData, "%f", &fx);
fscanf(pfData, "%f", &fy);
fscanf(pfData, "%f", &fz);
v->push_back(osg::Vec3(fx, fy, fz));
c->push_back(osg::Vec4(1.f, 0.f, 0.f, 0.3f));//用来设置颜色
countTwo++;
}
fclose(pfData);
}
//设置绘图基元的参数
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry();
geometry ->setVertexArray(v.get());
geometry ->setColorArray(c.get());//设置顶点颜色
geometry ->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
//设置法向量
osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array;
normals->push_back(osg::Vec3(0.0, -1.0, 0.0));
geometry ->setNormalArray(normals);
geometry ->setNormalBinding(osg::Geometry::BIND_OVERALL);
//创建三角网对象
osg::ref_ptr<osgUtil::DelaunayTriangulator> dt = new osgUtil::DelaunayTriangulator(v.get());
//生成三角网
dt->triangulate();
/* 遍历三角形 去除 */
//关键点 使用DrawElementsUInt 去接收
osg::ref_ptr<osg::DrawElementsUInt> de = dt->getTriangles();
osg::DrawElementsUInt::iterator iter;
unsigned int _size = de->size();
int a(0), x(0);
float th = 0.5;
for (iter = de->begin(); iter != de->end();)
{
osg::Vec3f pt1 = v->at(*iter);
osg::Vec3f pt2 = v->at(*(iter + 1));
osg::Vec3f pt3 = v->at(*(iter + 2));
double dis1 = getDistance(pt1, pt2);//getDistance() 函数 是我自己限制函数
double dis2 = getDistance(pt2, pt3);
double dis3 = getDistance(pt3, pt1);
//如果大于一定数值删除
if (dis3 > th || dis2 > th || dis1 > th)
{
iter = de->erase(iter, iter + 3); //
continue;
}
iter += 3;
}
//加入绘图基元
geometry->addPrimitiveSet(de); //此时加入的 是de 不是 dt->getTriangles();
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
geode->addDrawable(geometry.get());
//多边形绘制,正面反面都绘制
osg::ref_ptr<osg::PolygonMode> polymode = new osg::PolygonMode();
polymode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);//新
//状态
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();
//启用多边形绘制模式,并指定状态继承模式OVERRIDE
stateset->setAttributeAndModes(polymode, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
//多边形线绘制节点
osg::ref_ptr<osg::Group> wirframe_subgraph = new osg::Group;
wirframe_subgraph->setStateSet(stateset.get());
wirframe_subgraph->addChild(geometry.get());
return wirframe_subgraph.get();
}
//main
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
//创建组节点
osg::ref_ptr<osg::Group> root = new osg::Group();
//创建节点接受 相关节点数据
osg::ref_ptr<osg::Node> node = createPointAndOther().get();
root->addChild(node.get());
osgUtil::Optimizer optimizer;
optimizer.optimize(root.get());
viewer->setSceneData(root.get());
viewer->realize();
viewer->run();
return 0;
该处使用的url网络请求的数据。