使用OSG创建一个简单的地形
1.解决方案
在网上参考了一些资料,使用OSG创建地形最简单的办法就是使用OSG::HeightField类,它是描述类似于DEM网格的四角面片。首先给出具体实现代码:
#include <iostream>
#include <Windows.h>
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osg/Texture2D>
#include <osg/ShapeDrawable>
#include <gdal_priv.h>
using namespace std;
using namespace osg;
using namespace osgViewer;
//实现函数:从高程图创建地形
osg::Node* createHeightField(std::string heightFile, std::string texFile)
{
//读取高度文件
GDALAllRegister(); //GDAL所有操作都需要先注册格式
CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); //支持中文路径
GDALDataset* img = (GDALDataset *)GDALOpen(heightFile.c_str(), GA_ReadOnly);
if (!img)
{
return nullptr;
}
//读取基本参数
int imgWidth = img->GetRasterXSize(); //图像宽度
int imgHeight = img->GetRasterYSize(); //图像高度
int bandNum = img->GetRasterCount(); //波段数
int depth = GDALGetDataTypeSize(img->GetRasterBand(1)->GetRasterDataType()) / 8; //图像深度
//获取地理坐标信息
double padfTransform[6];
if (img->GetGeoTransform(padfTransform) == CE_Failure)
{
return nullptr;
}
double startX = padfTransform[0] + 0.5 * padfTransform[1]; //左上角点坐标X
double dX = padfTransform[1]; //X方向的分辨率
double startY = padfTransform[3] + padfTransform[5] * imgHeight - 0.5 * padfTransform[5]; //左下角点坐标Y
double dY = -padfTransform[5]; //Y方向的分辨率
//申请buf
int bufWidth = imgWidth;
int bufHeight = imgHeight;
size_t imgBufNum = (size_t)bufWidth * bufHeight * bandNum;
float *imgBuf = new float[imgBufNum];
//读取
size_t imgBufOffset = (size_t)bufWidth * (bufHeight - 1) * bandNum;
img->RasterIO(GF_Read, 0, 0, bufWidth, bufHeight, imgBuf + imgBufOffset, bufWidth, bufHeight,
GDT_Float32, bandNum, nullptr, bandNum*depth, -bufWidth*bandNum*depth, depth);
//定义并设置高度文件
osg::ref_ptr<osg::HeightField> heightField = new osg::HeightField();
heightField->allocate(imgWidth, imgHeight); //申请空间
heightField->setOrigin(osg::Vec3(startX, startY, 0)); //起始位置
heightField->setXInterval(dX); //间距X
heightField->setYInterval(dY); //间距Y
heightField->setSkirtHeight(1.0f);
//填充高度值
for (int r = 0; r < imgHeight; r++)
{
for (int c = 0; c < imgWidth; c++)
{
size_t m = (size_t)r * imgWidth + c;
heightField->setHeight(c, r, imgBuf[m]);
}
}
//释放
delete[] imgBuf;
imgBuf = nullptr;
//节点
osg::Geode* geode = new osg::Geode();
osg::ref_ptr<osg::ShapeDrawable> heightShape = new osg::ShapeDrawable(heightField.get());
geode->addDrawable(heightShape);
//设置纹理
osg::ref_ptr<osg::Image> texImage = osgDB::readImageFile(texFile);
osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
tex->setImage(texImage);
tex->setDataVariance(osg::Object::DYNAMIC);
//渲染状态
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();
stateset->setTextureAttributeAndModes(0, tex.get(), osg::StateAttribute::ON);
geode->setStateSet(stateset.get());
return geode;
}
int main()
{
osgViewer::Viewer viewer;
osg::ref_ptr<osg::Group> group = new osg::Group;
std::string heightFile = "D:\\Data\\dst.tif";
std::string texFile = "D:\\Data\\dom3_Level_19.jpg";
group->addChild(createHeightField(heightFile, texFile));
viewer.setSceneData(group);
viewer.setUpViewInWindow(100, 100, 800, 600);
return viewer.run();
}
其运行结果如下,显示的是美国大峡谷(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.参考文档
- osg三维重建的两种方法剖析:三角面片(osgUtil::DelaunayTriangulator)和四角面片(osg::HeightField)
- OSG从高程图创建地形-可运行
- OSG从高程图创建地形
使用OSG创建一个简单的地形的更多相关文章
- Directx11教程(19) 画一个简单的地形
原文:Directx11教程(19) 画一个简单的地形 通常我们在xz平面定义一个二维的网格,然后y的值根据一定的函数计算得到,比如正弦.余弦函数的组合等等,可以得到一个看似不错的地形或者 ...
- 如何创建一个简单的Visual Studio Code扩展
注:本文提到的代码示例下载地址>How to create a simple extension for VS Code VS Code 是微软推出的一款轻量级的代码编辑器,免费,开源,支持多种 ...
- 《Entity Framework 6 Recipes》翻译系列 (3) -----第二章 实体数据建模基础之创建一个简单的模型
第二章 实体数据建模基础 很有可能,你才开始探索实体框架,你可能会问“我们怎么开始?”,如果你真是这样的话,那么本章就是一个很好的开始.如果不是,你已经建模,并在实体分裂和继承方面感觉良好,那么你可以 ...
- 如何创建一个简单的C++同步锁框架(译)
翻译自codeproject上面的一篇文章,题目是:如何创建一个简单的c++同步锁框架 目录 介绍 背景 临界区 & 互斥 & 信号 临界区 互斥 信号 更多信息 建立锁框架的目的 B ...
- Windows 8.1 应用再出发 (WinJS) - 创建一个简单项目
前面几篇我们介绍了如何利用 C# + XAML 完成Windows Store App 功能的实现,接下来的几篇我们来看看如何利用 Html + WinJS 来完成这些功能. 本篇我们使用WinJS ...
- ADF_General JSF系列1_创建一个简单的JSF Application
2015-02-17 Creatd By BaoXinjian
- IntelliJ IDEA 15 部署Tomcat及创建一个简单的Web工程
一.部署Tomcat 二.创建一个简单的Web工程 2.1创建一个新工程 创建一个新工程 设置JDK及选择Web Application (创建的是Web工程) 点击Next,选择工作空间,起个工程名 ...
- Symfony2之创建一个简单的web应用
Symfony2——创建bundle bundle就像插件或者一个功能齐全的应用,我们在应用层上开发的应用的所有代码,包括:PHP文件.配置文件.图片.css文件.js文件等都会包含在bu ...
- 如何创建一个简单的struts2程序
如何创建一个简单的Struts2程序 “计应134(实验班) 凌豪” 1.创建一个新的Web项目test(File->new->Web Project) 2.Struts2框架的核心配置文 ...
随机推荐
- 原生javascript写自己的运动库(匀速运动篇)
网上有很多JavaScript的运动库,这里和大家分享一下用原生JavaScript一步一步写一个运动函数的过程,如读者有更好的建议欢迎联系作者帮助优化完善代码.这个运动函数完成后,就可以用这个运动函 ...
- js基础进阶--图片上传时实现本地预览功能的原理
欢迎访问我的个人博客:http://www.xiaolongwu.cn 前言 最近在项目上加一个图片裁剪上传的功能,用的是cropper插件,注意到选择本地图片后就会有预览效果,这里整理一下这种预览效 ...
- webpack bug及解决方案
1.webpack打包后z-index失效 解决方案:z-index设置成行内样式,例如:root.style.cssText = 'z-index:100000 !important;';
- 向Oracle数据库插入中文乱码解决方法
解决方法: 第一步:sqlplus下执行:select userenv('language') from dual;//查看oracle字符集 注:如果oracle字符集与后台代码设置的 ...
- Spring Boot 1.4测试的简单理解
首先maven要引入spring-boot-starter-test这个包. 先看一段代码 @RunWith(SpringRunner.class) @SpringBootTest(webEnviro ...
- golang自定义路由控制实现(二)-流式注册接口以及支持RESTFUL
先简单回顾一下在上一篇的文章中,上一篇我主要是结合了数组和Map完成路由映射,数组的大小为8,下标为0的代表Get方法,以此类推,而数组的值则是Map,键为URL,值则是我们编写对应的接口.但 ...
- 【原】用Java编写第一个区块链(一)
写这篇随笔主要是尝试帮助自己了解如何学习区块链技术开发. [本文禁止任何形式的全文粘贴式转载,本文来自 zacky31 的随笔] 目标: 创建一个最基本的"区块链" 实现一个简单的 ...
- Spring Boot 使用 AOP 实现页面自适应
鉴于复杂页面自适应的难度,一般会做几套模板分别适应手机.平板.电脑等设备.使用 Spring Boot 开发单体应用时,一般会使用 Thymeleaf 模板,那么可以使用 AOP 技术来实现页面自适应 ...
- java.exe进程来源排查录
解决后的一个小结:此处是一个tomcat端口,这种情况下,可以先在浏览器访问下看看效果,就可以快速定位 又发现一个简单的办法: 下面的定位过程,适用于各种场合 无意中发现有个进程开了好多端口,很奇怪 ...
- Docker for windows on VMware
工作环境 操作系统:Windows 10 Pro x64 Hyper-V:已卸载. VMware:已安装. Virtual Box:无安装. 前言 鉴于Hyper-V在Windows桌面系统下的&qu ...