osg 示例程序解析之osgdelaunay
轉自:http://lzchenheng.blog.163.com/blog/static/838335362010821103038928/
本示例程序主要說明如何用osgUtil::DelaunayTriangulator類建立約束的delaunay(德洛內)三角網,delaunay(德洛內)三角網主要用於基於離散點數據構建三維表面。如經常用於構建地形表面,本示例程序就是用該類構建一個地形,然后添加一些約束條件,在地形上繪制道路、區域等要素,示例程序的主要函數為:makedelaunay(),該函數輸入的參數是約束的數目,輸出的是一個組節點,下面對這個函數的實現進行說明。
1、生成離散點數據
該函數首先隨機生成一些離散點數據,代碼如下:
//隨機生成地形坐標點,存儲到Points中
int eod=0;
while(eod>=0) {
osg::Vec3d pos=getpt(eod);
if (pos.z()>-10000){
points->push_back(pos);
eod++;
}
else {
eod=-9999;
}
}
2、生成一些約束類,這些類派生與osgUtil::DelaunayConstraint,如
osg::ref_ptr<ArealConstraint> dc2; 約束區域
osg::ref_ptr<ArealConstraint> forest; 約束區域,作為一片樹林
osg::ref_ptr<LinearConstraint> dc3; 約束區域,一條線
等等,然后確定約束的邊或點,如當輸入的參數大於0時,確定金字塔的底邊作為約束邊,如下代碼所示:
//令5個金字塔的底邊作為約束邊
for(unsigned int ipy=0; ipy<5; ipy++){
osg::ref_ptr<pyramid>pyr=new pyramid;
float x=2210+ipy*120, y=1120+ipy*220;
//設置金字塔繪制的位置及大小尺寸
pyr->setpos(osg::Vec3(x,y,getheight(x,y)),125.0+10*ipy);
//確定金字塔底面4邊形4個頂點坐標
pyr->calcVertices(); //make vertices
//底面4條邊構成約束
pyr->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP,0,4) );
//添加約束邊,金字塔底面4邊形4條邊作為約束
trig->addInputConstraint(pyr.get());
//存儲約束邊
pyrlist.push_back(pyr.get());
}
addInputConstraint()方法用於向三角網中添加約束條件。
其余的約束條件的生成與添加與其類似。
3、三角化處理
添加完約束條件后,進行三角化處理,如下代碼所示:
trig->setInputPointArray(points);
osg::Vec3Array *norms=new osg::Vec3Array;
trig->setOutputNormalArray(norms);
//三角化處理
trig->triangulate();
4、將三角化的圖元添加到葉節點中
//添加構建的三角形作為圖元
gm->addPrimitiveSet(trig->getTriangles());
gm->setNormalArray(trig->getOutputNormalArray());
gm->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
geode->addDrawable(gm.get());
5、繪制約束的幾何體
為了方便看出約束的效果,我們用線框的方式顯示圖形,把葉節點的狀態改為線框顯示方式。
osg::PolygonMode *pLolyMode=new osg::PolygonMode();
pLolyMode->setMode(osg::PolygonMode::FRONT_AND_BACK ,osg::PolygonMode::LINE);
stateset->setAttribute(pLolyMode);
geode->setStateSet( stateset );
在繪制約束體之前,先要使用removeInternalTriangles()方法,移開約束條件構建的三角形,對於繪制金字塔的代碼:
for ( std::vector < pyramid* >::iterator itr=pyrlist.begin(); itr!=pyrlist.end(); itr++) {
//移開金字塔約束邊形成的三角形,形成4個4邊形空洞
//trig->removeInternalTriangles(*itr);
//繪制金字塔
//geode->addDrawable((*itr)->makeGeometry()); // this fills the holes of each pyramid with geometry
}
如果我們注釋以下兩句:
//trig->removeInternalTriangles(*itr);
//geode->addDrawable((*itr)->makeGeometry()); // this fills the holes of each pyramid with geometry
會看到如下的效果:

我們看到受約束的地方仍然形成了三角形,沒有生成生4邊形的空洞,如果我們把第一句的注釋去掉,會看到如下結果:

說明建立約束條件后,只有使用trig->removeInternalTriangles()方法,才能使約束生效,通過本示例程序,我們可以知道如何基於離散點及約束條件,構建受約束的三角網的方法