1.解决方案

在网上参考了一些资料,使用OSG创建地形最简单的办法就是使用OSG::HeightField类,它是描述类似于DEM网格的四角面片。首先给出具体实现代码:

  1. #include <iostream>
  2. #include <Windows.h>
  3. #include <osgViewer/Viewer>
  4. #include <osgDB/ReadFile>
  5. #include <osg/Texture2D>
  6. #include <osg/ShapeDrawable>
  7. #include <gdal_priv.h>
  8. using namespace std;
  9. using namespace osg;
  10. using namespace osgViewer;
  11. //实现函数:从高程图创建地形
  12. osg::Node* createHeightField(std::string heightFile, std::string texFile)
  13. {
  14. //读取高度文件
  15. GDALAllRegister(); //GDAL所有操作都需要先注册格式
  16. CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); //支持中文路径
  17. GDALDataset* img = (GDALDataset *)GDALOpen(heightFile.c_str(), GA_ReadOnly);
  18. if (!img)
  19. {
  20. return nullptr;
  21. }
  22. //读取基本参数
  23. int imgWidth = img->GetRasterXSize(); //图像宽度
  24. int imgHeight = img->GetRasterYSize(); //图像高度
  25. int bandNum = img->GetRasterCount(); //波段数
  26. int depth = GDALGetDataTypeSize(img->GetRasterBand(1)->GetRasterDataType()) / 8; //图像深度
  27. //获取地理坐标信息
  28. double padfTransform[6];
  29. if (img->GetGeoTransform(padfTransform) == CE_Failure)
  30. {
  31. return nullptr;
  32. }
  33. double startX = padfTransform[0] + 0.5 * padfTransform[1]; //左上角点坐标X
  34. double dX = padfTransform[1]; //X方向的分辨率
  35. double startY = padfTransform[3] + padfTransform[5] * imgHeight - 0.5 * padfTransform[5]; //左下角点坐标Y
  36. double dY = -padfTransform[5]; //Y方向的分辨率
  37. //申请buf
  38. int bufWidth = imgWidth;
  39. int bufHeight = imgHeight;
  40. size_t imgBufNum = (size_t)bufWidth * bufHeight * bandNum;
  41. float *imgBuf = new float[imgBufNum];
  42. //读取
  43. size_t imgBufOffset = (size_t)bufWidth * (bufHeight - 1) * bandNum;
  44. img->RasterIO(GF_Read, 0, 0, bufWidth, bufHeight, imgBuf + imgBufOffset, bufWidth, bufHeight,
  45. GDT_Float32, bandNum, nullptr, bandNum*depth, -bufWidth*bandNum*depth, depth);
  46. //定义并设置高度文件
  47. osg::ref_ptr<osg::HeightField> heightField = new osg::HeightField();
  48. heightField->allocate(imgWidth, imgHeight); //申请空间
  49. heightField->setOrigin(osg::Vec3(startX, startY, 0)); //起始位置
  50. heightField->setXInterval(dX); //间距X
  51. heightField->setYInterval(dY); //间距Y
  52. heightField->setSkirtHeight(1.0f);
  53. //填充高度值
  54. for (int r = 0; r < imgHeight; r++)
  55. {
  56. for (int c = 0; c < imgWidth; c++)
  57. {
  58. size_t m = (size_t)r * imgWidth + c;
  59. heightField->setHeight(c, r, imgBuf[m]);
  60. }
  61. }
  62. //释放
  63. delete[] imgBuf;
  64. imgBuf = nullptr;
  65. //节点
  66. osg::Geode* geode = new osg::Geode();
  67. osg::ref_ptr<osg::ShapeDrawable> heightShape = new osg::ShapeDrawable(heightField.get());
  68. geode->addDrawable(heightShape);
  69. //设置纹理
  70. osg::ref_ptr<osg::Image> texImage = osgDB::readImageFile(texFile);
  71. osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
  72. tex->setImage(texImage);
  73. tex->setDataVariance(osg::Object::DYNAMIC);
  74. //渲染状态
  75. osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();
  76. stateset->setTextureAttributeAndModes(0, tex.get(), osg::StateAttribute::ON);
  77. geode->setStateSet(stateset.get());
  78. return geode;
  79. }
  80. int main()
  81. {
  82. osgViewer::Viewer viewer;
  83. osg::ref_ptr<osg::Group> group = new osg::Group;
  84. std::string heightFile = "D:\\Data\\dst.tif";
  85. std::string texFile = "D:\\Data\\dom3_Level_19.jpg";
  86. group->addChild(createHeightField(heightFile, texFile));
  87. viewer.setSceneData(group);
  88. viewer.setUpViewInWindow(100, 100, 800, 600);
  89. return viewer.run();
  90. }

其运行结果如下,显示的是美国大峡谷(Grand Canyon)中的一小块:

1) 使用TIF格式的DEM

因为不太清楚别的网上资料里面地形文件是jpg格式的,要知道jpg格式只能8位且没有地理信息,所以在这里我直接使用的是GTiff格式的DEM。很奇怪我这里用osgDB读取TIF文件失败了,所以直接采用了GDAL读取。

2) 描述HeightField

使用GDAL打开高程文件(DEM),能够获取地形的起点位置和间距,将其填充到HeightField中,这样OSG就确定了高程点的XY位置。在使用GDAL读取高程文件(DEM)存储的高程值到内存中之后,依次填充到HeightField,就确定了地形的Z位置。最后绘制到节点,地形图也就绘制出来了。

2.存在问题

可以看到我这里采用的纹理文件是一个处理好的,范围刚刚好能够覆盖的jpg文件。其纹理是自动贴到四个角点的。其实我最初的设想是采用一个DOM(正射影像图)来实现,通过其地理位置确定纹理坐标,最终无视范围大小,实现一个DEM(高程)与DOM(影像)的自动叠加。

问题就在于HeightField的点是内部绘制的,我给其赋予的纹理坐标总是不正确。我初步尝试发现一个网格点需要2个纹理坐标才能把整个纹理填满。在这里希望大家批评指正下,究竟如何给HeightField的点设置纹理位置。

3.参考文档

  1. osg三维重建的两种方法剖析:三角面片(osgUtil::DelaunayTriangulator)和四角面片(osg::HeightField)
  2. OSG从高程图创建地形-可运行
  3. OSG从高程图创建地形

使用OSG创建一个简单的地形的更多相关文章

  1. Directx11教程(19) 画一个简单的地形

    原文:Directx11教程(19) 画一个简单的地形       通常我们在xz平面定义一个二维的网格,然后y的值根据一定的函数计算得到,比如正弦.余弦函数的组合等等,可以得到一个看似不错的地形或者 ...

  2. 如何创建一个简单的Visual Studio Code扩展

    注:本文提到的代码示例下载地址>How to create a simple extension for VS Code VS Code 是微软推出的一款轻量级的代码编辑器,免费,开源,支持多种 ...

  3. 《Entity Framework 6 Recipes》翻译系列 (3) -----第二章 实体数据建模基础之创建一个简单的模型

    第二章 实体数据建模基础 很有可能,你才开始探索实体框架,你可能会问“我们怎么开始?”,如果你真是这样的话,那么本章就是一个很好的开始.如果不是,你已经建模,并在实体分裂和继承方面感觉良好,那么你可以 ...

  4. 如何创建一个简单的C++同步锁框架(译)

    翻译自codeproject上面的一篇文章,题目是:如何创建一个简单的c++同步锁框架 目录 介绍 背景 临界区 & 互斥 & 信号 临界区 互斥 信号 更多信息 建立锁框架的目的 B ...

  5. Windows 8.1 应用再出发 (WinJS) - 创建一个简单项目

    前面几篇我们介绍了如何利用 C# + XAML 完成Windows Store App 功能的实现,接下来的几篇我们来看看如何利用 Html + WinJS 来完成这些功能. 本篇我们使用WinJS ...

  6. ADF_General JSF系列1_创建一个简单的JSF Application

    2015-02-17 Creatd By BaoXinjian

  7. IntelliJ IDEA 15 部署Tomcat及创建一个简单的Web工程

    一.部署Tomcat 二.创建一个简单的Web工程 2.1创建一个新工程 创建一个新工程 设置JDK及选择Web Application (创建的是Web工程) 点击Next,选择工作空间,起个工程名 ...

  8. Symfony2之创建一个简单的web应用

    Symfony2——创建bundle       bundle就像插件或者一个功能齐全的应用,我们在应用层上开发的应用的所有代码,包括:PHP文件.配置文件.图片.css文件.js文件等都会包含在bu ...

  9. 如何创建一个简单的struts2程序

    如何创建一个简单的Struts2程序 “计应134(实验班) 凌豪” 1.创建一个新的Web项目test(File->new->Web Project) 2.Struts2框架的核心配置文 ...

随机推荐

  1. arcEngine开发之activeView.PartialRefresh(译)

    为什么要使用partialRefresh arcMap应用程序窗口操作主要是由 IActiveView 控制的,并且它有 Map(data view) 和 PageLayout(layout view ...

  2. markdown 一分钟入门

    markdown 很好的一门标记语言 语法简单,记住下面的就入门了,一分钟不到 使用范围广,各式各样的编辑器支持markdown,评论也是支持的, 一般文档后缀为.md markdown 基本用法记住 ...

  3. 微信小程序AES解密失败

    微信小程序分享群获取群id时后端接口返回"微信AES解密失败",后来定位到原因是服务端用于解密的session_key失效.用户获取到openID存在缓存后,就不会每次login获 ...

  4. mybatis自定义代码生成器(Generator)——自动生成model&dao代码

    花了两天的时间研究了下mybatis的generator大体了解了其生成原理以及实现过程.感觉generator做的非常不错,给开发者也留足了空间.看完之后在generator的基础上实现了自定义的生 ...

  5. Python Selenium 之生成Beautiful可视化报告

    提到自动化测试,少不了自动化生成测试报告,更少不了漂亮的测试报告呀!刚好看到在github上有个大神分享了BeautifulReport,与unittest测试框架完美的结合起来,就能生成Beauti ...

  6. pycharm跨目录调用文件

    笔者今天在一个测试qq群中遇到解决跨目录中调用文件的问题.现在来详细说一下. 以下图目录为例: 1.同目录下直接调用掉用.test2.py和test3.py在同一个目录test2下. 所以在test3 ...

  7. selenium之 坑(StaleElementReferenceException: Message: Element not found in the cache...)

    今天给大家分享一个selenium中经常会有人遇到的坑: selenium.common.exceptions.StaleElementReferenceException: Message: Ele ...

  8. balance.go 源码阅读

    ) //10s +随机毫秒数 后 执行下面代码     for _ = range t {         for _, v := range pBackendSvrs {             i ...

  9. noip 2015 斗地主 大爆搜!!!

    反正肯定是大模拟 但是每一个可以出的牌都搜一定不是最优的 考虑最特殊的出牌方案:顺子(单,对,三) 每一种方案再加上暴力贪心打出剩下的牌的步数 #include<cstdio> #incl ...

  10. h5仿微信聊天(高仿版)、微信聊天表情|对话框|编辑器

    之前做过一版h5微信聊天移动端,这段时间闲来无事就整理了下之前项目,又重新在原先的那版基础上升级了下,如是就有了现在的h5仿微信聊天高仿版,新增了微聊.通讯录.探索.我四个模块 左右触摸滑屏切换,聊天 ...