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

會看到如下的效果:

osg 示例程序解析之osgdelaunay - 陳恆 - 陳恆的博客

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

osg 示例程序解析之osgdelaunay - 陳恆 - 陳恆的博客

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



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章