OsgDelaunay三角网绘制及其如何限制生成的三角形

主要参考资料: 《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网络请求的数据。


总结

OSG限制三角网实现并不难,难得是这方面资料太难找。在这个里面最重要一条,获取三角形顶点索引,和删除三角形顶点索引时候切记删除三个,删除连续的三个,否则会出现问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值