一、几何体
大家都知道场景都是由基本的绘图基元构成的,基本的绘图基元构成简单的几何体,简单的儿何体构成复杂的几何体,复杂的几何体最终构造成复杂的场景。当多个几何体组合时,可能存在多种降低场景渲染效率的原因。在很多3D引擎中,都提供了对场景的几何体进行修改的操作,以达到最优渲染效率。虽然最优渲染效率只是一个理想状态,但一定的几何体操作在相当程度上可以提高渲染效率。
在OSG中,为了获得所需的性能和渲染的效率,osgUtil 库提供了一些通用的几何体运算,这些几何体运算主要包括osgUil::simplifier (简化)、osgUil:smoothingVisitor (生成法线)、osgUtil:DelaunayTriangulator (生成Delaunay三角网工具)和ostUl:TriStripVisitor (条带化)等。下面就来介绍几种常用的几何体操作。
二、简化几何体
简化几何体(osgiUil:Simplifier) 类继承自osg:NodeVisitor类,它采用访问器的方式遍历几何体 osgUitl::Simplifier 的继承关系图osiUl:Sipliierin类对几何体的简化主要需要设置两个方面的参数,即当几何体样本比率小于1时,设置点的误差限制:当几何体的样本比率大于1时,设置边的长度限制。通过对点的误差或者边的长度的限制简化不必要的点和边,然后通过平滑处理和条带化渲染几何体,进而达到提高渲染效率的目的,也可以用于自动生成低层次模型。一般来说,样本比率越大,简化越少;样本比率越小,简化越多。优化可以直接调用下面的函数:
virtual void apply(osg:;Geode &geode) /应用于叶节点
void simplify(osg:Geomctry &geometry)/简化几何体
这两个函数同样可用于osg::Node节点,不过,关联实例时需要使用accept0方法osgUtil:Simplifier简化采用的是边塌陷算法,对于这个算法笔者并没有深入研究。目前,网上很少有关于这方面的文档。
三、简化几何体的案例
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osg/Node>
#include <osg/Geode>
#include <osg/Group>
#include <osg/PositionAttitudeTransform>
#include <osgDB/Readfile>
#include <osgDB/WriteFile>
#include<osgGA/StateSetManipulator>
#include <osgUtil/Optimizer>
#include <osgUtil/Simplifier>
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();
//设置样本比率,样本简化比率越大,简化越小
//样本比率越小简化越多
float sampleRatio = 0.3f;
//设置点的最大误差
float maxError = 4.0f;
//创建简化对象
osgUtil::Simplifier simplifiter(sampleRatio, maxError);
//读取牛模型
osg::ref_ptr<osg::Node> nodel = osgDB::readNodeFile("cow.osg");
//深拷贝牛的模型到node2节点
osg::ref_ptr<osg::Node> node2 = (osg::Node*)(nodel->clone(osg::CopyOp::DEEP_COPY_ALL));
//创建位置变化节点
osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform();
//设置位节点
pat->setPosition(osg::Vec3(10.0f, 0.0f, 0.0f));
//添加子节点
pat->addChild(node2.get());
//简化处理
pat->accept(simplifiter);
//添加场景
root->addChild(nodel.get());
root->addChild(pat.get());
// 优化场景数据
osgUtil::Optimizer optimizer;
optimizer.optimize(root.get());
//设置场景数据
viewer->setSceneData(root.get());
//初始化并创建窗口
viewer->realize();
//viewer->setUpViewInWindow(200, 200, 800, 800);
viewer->run();
return 0;
}

四、Delaunay 三角网绘制
4.1. TIN模型
在数字地形建模中,不规则三角网(TIN)通过从不规则离散分布的数据点生成的连续三角面来逼近地形表面。就表达地形信息的角度而言,TIN模型的优点是它能以不同层次的分辨率来描述地形表面。与格网数据模型相比,TIN模型在某一特定分辨率下能用更少的空间和时间更精确地表示更加复杂的表面。特别是当地形包含有大量特征,如断裂线、构造线时,TIN 模型能更好地顾及这些特征,从而能更精确合理地表达地表形态。对于TIN模型,其基本要求有以下3点:
(1) TIN是唯一的。
(2)力求最佳三角形几何形状。
(3)保证最邻近的点构成三角形。
在所有可能的三角网中,狄洛尼(Delaunay) 三角网在地形拟合方面表现最为出色,常用于TIN的生成。当不相交的断裂线等被作为预先定义的限制条件作用于TIN的生成当中时,就必须考虑带约束条件的狄洛尼三角网。
目前,狄洛尼三角网生成的算法比较多,传统的算法主要包括两种,即Lawson算法以及Bowyer-Watson算法。后来经过该传统算法改进的算法就多了,这里不专门对这些算法予以介绍,可参考相关论文。
4.2. osgtli::DelaunayTriangulator 类
上面介绍了狄洛尼(Delaunay)三角网的特性、生成算法及应用,下面来看一下OSG中的狄洛尼三角网。创建狄洛尼三角网有如下3个步骤:
(1)创建项点数组。
(2)创建一个osgUtil:DelaunayTriangulator对象,并初始化顶点数组,同时生成三角网,程序代码如下:
bool triangulate()//开始生成三角网格
(3)创建一个几何体对象,把osgUil:DelaunayTriangulator类对象生成的绘制图元加入到几何体中。在生成狄洛尼三角网时,读者还可以添加一一些限制条件,限制条件可以是点、线或多边形,例如:
void addInputConstraint(DelaunayConstraint *dc)/添加限制条件
通过这么多的讲解,读者应该清楚了狄洛尼三角网的绘制方法了吧。有兴趣的读者可以研究关于狄洛尼三角网的算法。
五、Delaunay三角网绘制示例
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osg/Node>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Group>
#include <osgGA/StateSetManipulator>
#include <osgDB/Readfile>
#include <osgDB/Writefile>
#include <osgUtil/Optimizer>
#include <osgUtil/DelaunayTriangulator>
#include "Tex.h"
typedef unsigned int Unit;
int main()
{
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::Vec3Array> coords = new osg::Vec3Array();
//计算顶点数组的大小
unsigned int n = sizeof(vertex) / sizeof(float[3]);
//添加顶点数据
for (Unit i = 0; i < n; i++)
{
coords->push_back(osg::Vec3(vertex[i][0], vertex[i][1], vertex[i][2]));
}
//创建Delauny三角网对象
osg::ref_ptr<osgUtil::DelaunayTriangulator> dt = new osgUtil::DelaunayTriangulator(coords.get());
//生产三角网
dt->triangulate();
//创建几何体
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry();
//设置顶点数组
geometry->setVertexArray(coords.get());
//加入到绘图单元
geometry->addPrimitiveSet(dt->getTriangles());
//添加到叶子节点
osg::ref_ptr<osg::Geode> geode = new osg::Geode();
geode->addDrawable(geometry.get());
root->addChild(geode.get());
//优化场景数据
osgUtil::Optimizer optimizer;
optimizer.optimize(root.get());
//设置场景数据
viewer->setSceneData(root.get());
//初始化并创建窗口
viewer->realize();
//viewer->setUpViewInWindow(200, 200, 800, 800);
viewer->run();
return 0;
}
