三角带绘制

490 阅读3分钟

1 三角带绘制

三角带绘制(osgUtil::TriStripVisitor)类继承自 osgUtil::BaseOptimizerVisitor 类,它采用访问器的机制遍历场景中的几何体,实现三角带绘制,以提高渲染效率. osgUtil::TriStripVisitor的继承关系图如图所示。

2.png

下面对 osgUtil::TriStripVisitor 的两个常用成员函数予以说明:

void stripify(ong::Geometry &drawable) // 条带化几何体

virtual void apply(osg::Geode &geode)// 应用于叶节点

从上面可以看出,它同样可应用于叶节点,值得注意的是,关联叶节点实例时需要调用accept方法。

大多数图形卡并不直接支持索引三角网。在渲染三角形时,一般是将 3 个顶点同时提交,这样,共享的顶点会多次提交,三角形用到一次就提交一次。因为内存和图形硬件间的数据传输是瓶颈,所以很多API和硬件支持特殊的三角网格式以减少传输量,基本思想是排序点和面,使显卡中已有的三角形不需要再次传输。

这里,我们只讨论三角带,三角带是一个三角形列表,其中每个三角形都与前一个三角形共享一边,在一种最理想的状态下,三角带可以用N+2个顶点表示存储N个面.N很大时,每个三角形平均发送一个顶点。在实践中,很多情况下,很多网格是一个三角带无法表达的,此时就需要多个三角带来联合绘制,因为我们希望最小化发往图形卡的顶点数,所以,三角带的数目应该尽可能得少,即三角带越长越好。从另一个方面来说,分别渲染两个长度为N的三角带所需要的时间比渲染一个长度为2N的三角带要长,即使2N的三角带中三角形的个数多于两个分开的三角带中的三角形个数的和,因为建立各三角带需要额外的处理时间。

学习了上面的基础知识,读者再去看关于这部分的源代码就会感觉非常易懂了,这些更多是原理的问题。

2 三角带绘制示例

三角带绘制(osgUtil::TriStripVisitor)示例的代码如程序清单所示。

#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>

#include <osg/Node>
#include <osg/Geode>
#include <osg/Group>

#include <osgDB/ReadFile>
#include <osgDB/WriteFile>

#include <osgGA/StateSetManipulator>

#include <osgUtil/Optimizer>
#include <osgUtil/TriStripVisitor>

#include "utility.h"

//创建一个四边形节点
osg::ref_ptr<osg::Geometry> 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(0, vt.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));

	//设置颜色数组
	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::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));

	return geom.get();
}

int main()
{
	//创建Viewer对象,场景浏览器
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
	//方便查看在多边形之间切换,以查看三角网
	viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));

	osg::ref_ptr<osg::Group> root = new osg::Group();

	//创建一个几何体对象
	osg::ref_ptr<osg::Geometry> geometry = createQuad();

	//对几何体进行条带化
	osgUtil::TriStripVisitor stripper;
	stripper.stripify(*(geometry.get()));

	//添加到叶节点
	osg::ref_ptr<osg::Geode> geode = new osg::Geode();
	geode->addDrawable(geometry.get());

	//添加到场景
	root->addChild(geode.get());

	//优化场景数据
	osgUtil::Optimizer optimizer;
	optimizer.optimize(root.get());

	setWindowSize(viewer.get(), 700, 400, "TriStripVisitor");

	viewer->setSceneData(root.get());

	viewer->realize();

	viewer->run();

	return 0;
}

效果图1

3.PNG

效果图2

4.PNG

动态效果图

动画.gif