最近项目中需要利用osg重建三维曲面,所以学习了一下。

第一,我先用的狄洛尼三角形的方法,即osgUtil::DelaunayTriangulator,用这种方法的特点是:

1.首先必须给其一个存储三维点集的数组,该方法会对这些杂乱无章的散点自动排序,然后就利用这些排好序的,符合三角网构建规则的散点去构建三角网,需要注意的是经过dt->setInputPointArray(coords);这句话以后,数组coords的值的顺序已经发生改变,不再是原来的coords。

2.再给其贴纹理的时候,必须要首先设置一个颜色数组给它,需要注意的是,纹理的坐标都是0~1范围的,而且是二维的(x,y),所以必须将coords的坐标的x和y值一 一 映射到0~1的范围。

3.必须输出法向量,并用该法向量数组给对应的geometry赋值

具体代码如下:

//创建Delaunay三角网对象
 osg::ref_ptr<osgUtil::DelaunayTriangulator> dt = new osgUtil::DelaunayTriangulator();
 dt->setInputPointArray(coords);//赋给它三维点集数组
 dt->setOutputNormalArray(normals);//输出法向量
 //生成三角网
 dt->triangulate();
 osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry();
 //设置坐标
 geometry->setVertexArray(coords.get());
 //设置描述
 geometry->addPrimitiveSet(dt->getTriangles());
 //设置法线
 geometry->setNormalArray(normals.get());
 geometry->setNormalBinding(osg::Geometry::BIND_PER_PRIMITIVE);
 //设置纹理坐标(纹理填充)
 osg::ref_ptr<osg::Vec2Array> texCoords = ComputerTextureCoords(*(coords.get()));//得到一 一映射后的范围在0~1的二维纹理数组
 geometry->setTexCoordArray(0,texCoords.get());

//尝试颜色填充
//  osg::ref_ptr<osg::Vec4Array> vextexColorArray = ComputePerVertexColor(*(coords.get()),getOSGColorTable());
//  geometry->setColorArray(vextexColorArray );
//  geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);

//准备纹理图像

//生成一副QImage,给其每个像素用事先定义好的颜色赋值。最后保存成png图像,保存方式就是image.save(strPath)参数是保存全文件名,包括路径和后缀。

QImage image(xCount,yCount,QImage::Format_Indexed8);
  QVector<QRgb> colorTable = getColorTable();
 image.setColorTable(colorTable); 
 InterpolateAndDrawImage(vecZs,&image,xCount,yCount,xCount,yCount); 
 QString strName = ::GetImagePath() + pContourData->GetName() +".png";
 image.save(strName);//保存成png图像

//开始用png图像生成纹理
  osg::ref_ptr<osg::Image> texImage = osgDB::readImageFile(strName.toStdString());

osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
 tex->setImage(texImage.get());
 tex->setDataVariance(osg::Object::DYNAMIC);

osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();
 stateset->setTextureAttributeAndModes(0,tex.get(),osg::StateAttribute::ON);

osg::ref_ptr<osg::Geode> geode = new osg::Geode();
 geode->addDrawable(geometry.get());
 geode->setStateSet(stateset.get());

//设置矩阵变换矩阵
 m_pRootSwitch->addChild(geode);

这样利用三角面片重建三维曲面,并且给其贴纹理渲染的效果就已经出来了,但是需要注意的是如果点集是规则网格数据,这种方式的构建就不适合了,应该用四角面片osg::HeightField的方式。

二、四边形面片

这种方式构建的特点如下:

1必须给其分配一个行列号,即构建出的网格有多少行多少列,利用allocate(unsigned int rownum,unsigned int columnnum)函数来分配。

2.必须给其指定一个初始位置,用setOrigin((const osg::Vec3& origin)来指定,注意三维顶点数组的z轴设为0即可,点集合中最小的x、y即可。

3.必须给其指定x和y方向每行每列之间的间隔用setXInterval(float dx );setYInterval(float dy)来指定。

4.有了初始位置,行列号,和间隔,就可以算出四边形面片每个顶点的位置了,然后在每个位置上设置高程值即可,用setHeight(float height)

具体实现过程如下,纹理渲染过程与三角面片类似,只是少了一个步骤就是:不需要给其设置纹理坐标,跟简单容易。

osg::ref_ptr<osg::HeightField> pHeightField = new osg::HeightField();
 pHeightField->allocate(xCount,yCount);
 pHeightField->setOrigin(osg::Vec3(xMin,yMin,0));
 pHeightField->setXInterval( xdelta );
 pHeightField->setYInterval( ydelta );
 
 float x,y;
 for(int i = 0; i < yCount; i++)
 {
  for(int j = 0; j < xCount; j++)
  {
   x = xMin + j * xdelta;
   y = yMin + i * ydelta;
   double z = pInterpolater->GetInterpolatedZ(x,y,input.begin(),input.end());
   vecZs.push_back(-z+zMin);
   coords->push_back(GeoToGeoNormal(osg::Vec3f(x,y,0)));
   
   pHeightField->setHeight(j,yCount-i-1,-z);//循环得到每个顶点,然后为其设置z值
  }
 }

///绘制纹理图像
 QImage image(xCount,yCount,QImage::Format_Indexed8);
  QVector<QRgb> colorTable = getColorTable();
 image.setColorTable(colorTable); 
 InterpolateAndDrawImage(vecZs,&image,xCount,yCount,xCount,yCount); 
 QString strName = ::GetImagePath() + pContourData->GetName() +".png";
 image.save(strName);
  osg::ref_ptr<osg::Image> texImage = osgDB::readImageFile(strName.toStdString());

osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
 tex->setImage(texImage.get());
 tex->setDataVariance(osg::Object::DYNAMIC);

osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();
 stateset->setTextureAttributeAndModes(0,tex.get(),osg::StateAttribute::ON);

osg::ref_ptr<osg::Geode> geode = new osg::Geode();
 geode->addDrawable(new osg::ShapeDrawable(pHeightField.get()));
 geode->setStateSet(stateset.get());

//附录:贴纹理用到的三个函数:

第一个将真实顶点坐标一 一映射到(0~1)的范围

osg::ref_ptr<osg::Vec2Array>  COSG3DSurfaceNode::ComputerTextureCoords( const osg::Vec3Array & vp)
{
 osg::ref_ptr<osg::Vec2Array> texCoords = new osg::Vec2Array();
 int nSize = vp.size();
 
 float maxX = vp[0].x();
 float minX = maxX;
 float maxY = vp[0].y();
 float minY = maxY;

for (int i=0;i<nSize;i++)
 {
  maxX = maxX<vp[i].x()?vp[i].x():maxX;
  minX = minX>vp[i].x()?vp[i].x():minX;
  maxY = maxY<vp[i].y()?vp[i].y():maxY;
  minY = minY>vp[i].y()?vp[i].y():minY;
 }

for(int i = 0;i< nSize; i++)
 {
  float xValue = 1-(maxX-vp[i].x())/(maxX - minX);
  //float yValue = 1-(maxY-vp[i].y())/(maxY - minY);
  float yValue = 1-(vp[i].y()-minY)/(maxY - minY);
  texCoords->push_back(osg::Vec2(xValue,yValue));
 }
 
 return texCoords;
}

第二,由颜色配置文件得到颜色数组

QVector<QRgb> COSG3DSurfaceNode::getColorTable()
{
 QVector<QRgb> table;

QString colotpath = ::GetImagePath() + "colorbar.txt";
 QFile file(colotpath);
 if (!file.open(QIODevice::ReadOnly))
 {
  assert(false);
 }

QTextStream WXStream(&file);
 for (int i=0;i<32;i++)
 {  
  float RColor(0.0),GColor(0.0),BColor(0.0),AColor(1.0);
  osg::Vec4  Vcolor;
  WXStream>>RColor>>GColor>>BColor;
  table.push_back(qRgb(RColor*255,GColor*255,BColor*255));  
 }

return table;
}

第三、生成纹理图像,根据颜色配置文件对图像像素 一 一进行赋值

void COSG3DSurfaceNode::InterpolateAndDrawImage(const std::vector<float>& vecData,QImage* pImage,int xCount,int yCount,int imageSizeX,int imageSizeY)
{
 assert(xCount > 0);
 assert(yCount > 0);
 assert(vecData.size() == xCount * yCount);

float min = vecData[0]; 
 float max = vecData[0];
 for(int i = 0; i < vecData.size() ; i++)
 {

if(max < vecData[i]) max = vecData[i];
  if(min > vecData[i]) min = vecData[i];
 }

double colorFactor = getColorTable().size() / (max - min);
 /// todo 图片插值
 for(int i = 0; i < imageSizeX; i++)
 {
  for(int j = 0; j < imageSizeY; j++)
  {
   pImage->setPixel(i,j,(vecData[j*xCount + i] - min) * colorFactor );   
  }
 }
 pImage->save(::GetImagePath() + "123.png");
}

m_pRootSwitch->addChild(geode);

最终效果图:



osg三维重建的两种方法剖析:三角面片(osgUtil::DelaunayTriangulator)和四角面片(osg::HeightField)相关推荐

  1. SQL Server中灾难时备份结尾日志(Tail of log)的两种方法

    简介 在数据库数据文件因各种原因发生损坏时,如果日志文件没有损坏.可以通过备份结尾日志(Tail of log)使得数据库可以恢复到灾难发生时的状态. 例如: 上图中.在DB_1中做了完整备份,在Lo ...

  2. C++/C++11中用于定义类型别名的两种方法:typedef和using

    类型别名(type alias)是一个名字,它是某种类型的同义词.使用类型别名有很多好处,它让复杂的类型名字变得简单明了.易于理解和使用,还有助于程序员清楚地知道使用该类型的真实目的.在C++中,任何 ...

  3. jquery-12 折叠面板如何实现(两种方法)

    jquery-12 折叠面板如何实现(两种方法) 一.总结 一句话总结:1.根据点击次数来判断显示还是隐藏,用data方法保证每个元素一个点击次数:2.找到元素的下一个,然后toggle实现显示隐藏. ...

  4. java 匿名list,java创造匿名对象的两种方法

    在java中有时候需要一些匿名对象的使用.可能有些小伙伴拿还不会创造,其实我们在学习一些方法时都或多或少的接触过.本篇所要讲到的创造匿名对象总结了两种方法,分别是静态工具方法和Lambda表达式,我们 ...

  5. Android Studio导入Eclipse项目的两种方法

    Android Studio导入Eclipse项目有两种方法,一种是直接把Eclipse项目导入Android Studio,另一种是在Eclipse项目里面进行转换,然后再导入Android Stu ...

  6. Response.Redirect 打开新窗体的两种方法

    普通情况下,Response.Redirect 方法是在server端进行转向,因此,除非使用 Response.Write("<script>window.location=' ...

  7. centos下两种方法安装git

    centos 5 64位下两种方法安装git 这里来给大家介绍下编译安装和yum安装git.   系统:centos 5.5 64位   需要的软件包:git-latest.tar.gz epel-r ...

  8. mysql创建库几种方法_MySQL创建数据库的两种方法

    本文为大家分享了两种mysql创建数据库的方法,供大家参考,具体内容如下 第一种方法:使用 mysqladmin 创建数据库使用普通用户,你可能需要特定的权限来创建或者删除 mysql 数据库. 所以 ...

  9. 牛客 Tree(最小深度总和)(两种方法求重心)难度⭐⭐⭐

    题目链接 牛妹有一张连通图,由n个点和n-1条边构成,也就是说这是一棵树,牛妹可以任意选择一个点为根,根的深度deprootdep_{root}deproot​​为0,对于任意一个非根的点,我们将他到 ...

最新文章

  1. 【Python】轻量级分布式任务调度系统-RQ
  2. 算法导论之多项式与快速傅里叶变换
  3. 【PP物料】物料主档备忘录
  4. 容器内存释放问题(STL新手笔记)
  5. 如何诊断ORA-125XX连接问题
  6. 自动生成网络拓扑图开源_为视频自动生成字幕,一款神奇的开源工具!
  7. 第三代英特尔至强可扩展处理器,英特尔数据中心的“芯法宝”
  8. 程序员:代码全部替换成中文,你能接受吗?
  9. 前端 input怎么显示null_前端架构 101(二): MVC 初探
  10. 笔者使用macOS的一些经验点滴记录1
  11. 分页缓冲池内存过高_揭秘:为什么新买的8G内存却显示4G可用,是系统出错还是被人坑了?...
  12. Android jdwp 自动断开,android – 安装调试器有时会导致应用程序崩溃
  13. 五分钟就能上手的Android APP开发入门教程!!!
  14. 合取式/合取范式/主合取范式/重言式/矛盾式 基本概念
  15. 股票交易接口是什么?
  16. Pytorch:训练中断再恢复时的注意事项
  17. graphpad画生存曲线怎么样去掉删失点_Graphpad 作图教程 | 这份超详细的生存曲线绘制指南,科研新手一看就会!...
  18. 使用RSD对高分1号卫星数据进行批量大气校正
  19. Java excel导出压缩zip并加密(拿起即用,有用请点赞,不做白嫖怪!)
  20. Linux【shell】 shell编程

热门文章

  1. 雀雀JavaScript基础Note2
  2. 申宝在线炒股三大指数全线上涨
  3. 记录VITE Vue3开发需要的一些常用插件
  4. Linux网络工具之fping
  5. 【图像检测】LSD直线检测【含Matlab源码 1697期】
  6. win10安装MinGW-64安装版
  7. 2018年 前端秋季校招面经
  8. 金融信息安全实训--密码与账户锁定策略、弱口令爆破
  9. qpixmap mysql_python – 将blob图像数据加载到QPixmap中
  10. Fedora 25 NTP服务器配置